Move "ostadmin" => "ostree admin"
authorColin Walters <walters@verbum.org>
Sat, 8 Sep 2012 22:46:50 +0000 (18:46 -0400)
committerColin Walters <walters@verbum.org>
Sat, 8 Sep 2012 23:34:10 +0000 (19:34 -0400)
This helps us avoid polluting the global binary namespace.

31 files changed:
Makefile-ostadmin.am [deleted file]
Makefile-ostree.am
Makefile.am
src/ostadmin/grub2/15_ostree [deleted file]
src/ostadmin/kernel/15_ostree_remove [deleted file]
src/ostadmin/kernel/15_ostree_update [deleted file]
src/ostadmin/main.c [deleted file]
src/ostadmin/ot-admin-builtin-deploy.c [deleted file]
src/ostadmin/ot-admin-builtin-diff.c [deleted file]
src/ostadmin/ot-admin-builtin-init.c [deleted file]
src/ostadmin/ot-admin-builtin-update-kernel.c [deleted file]
src/ostadmin/ot-admin-builtins.h [deleted file]
src/ostadmin/ot-admin-functions.c [deleted file]
src/ostadmin/ot-admin-functions.h [deleted file]
src/ostadmin/ot-admin-main.c [deleted file]
src/ostadmin/ot-admin-main.h [deleted file]
src/ostree/grub2/15_ostree [new file with mode: 0755]
src/ostree/kernel/15_ostree_remove [new file with mode: 0755]
src/ostree/kernel/15_ostree_update [new file with mode: 0755]
src/ostree/main.c
src/ostree/ot-admin-builtin-deploy.c [new file with mode: 0644]
src/ostree/ot-admin-builtin-diff.c [new file with mode: 0644]
src/ostree/ot-admin-builtin-init.c [new file with mode: 0644]
src/ostree/ot-admin-builtin-update-kernel.c [new file with mode: 0644]
src/ostree/ot-admin-builtins.h [new file with mode: 0644]
src/ostree/ot-admin-functions.c [new file with mode: 0644]
src/ostree/ot-admin-functions.h [new file with mode: 0644]
src/ostree/ot-builtin-admin.c [new file with mode: 0644]
src/ostree/ot-builtins.h
src/ostree/ot-main.c
src/ostree/ot-main.h

diff --git a/Makefile-ostadmin.am b/Makefile-ostadmin.am
deleted file mode 100644 (file)
index 45cb2d0..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2012 Colin Walters <walters@verbum.org>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-if !TRIGGERS_ONLY
-bin_PROGRAMS += ostadmin
-endif
-
-ostadmin_SOURCES = src/ostadmin/main.c \
-       src/ostadmin/ot-admin-builtins.h \
-       src/ostadmin/ot-admin-builtin-init.c \
-       src/ostadmin/ot-admin-builtin-diff.c \
-       src/ostadmin/ot-admin-builtin-deploy.c \
-       src/ostadmin/ot-admin-builtin-update-kernel.c \
-       src/ostadmin/ot-admin-functions.h \
-       src/ostadmin/ot-admin-functions.c \
-       src/ostadmin/ot-admin-main.h \
-       src/ostadmin/ot-admin-main.c \
-       $(NULL)
-
-ostadmin_CFLAGS =  $(AM_CFLAGS) -I$(srcdir)/src/libgsystem -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -I$(srcdir)/src/ostadmin -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS)
-ostadmin_LDADD = libgsystem.la libotutil.la libostree.la $(OT_INTERNAL_GIO_UNIX_LIBS)
-
-if ENABLE_KERNEL_UPDATES
-
-grub2dir = $(sysconfdir)/grub.d
-grub2_SCRIPTS = src/ostadmin/grub2/15_ostree
-
-kernelpostinstdir = $(sysconfdir)/kernel/postinst.d
-kernelpostinst_SCRIPTS = src/ostadmin/kernel/15_ostree_update
-
-kernelprermdir = $(sysconfdir)/kernel/prerm.d
-kernelprerm_SCRIPTS = src/ostadmin/kernel/15_ostree_remove
-
-endif
index 571b07f0a9dbe3f4784c8571a9e138f270f6c06f..59b4775ec9a09962fa95bff9d0c07751bc48e301 100644 (file)
@@ -23,6 +23,7 @@ endif
 
 ostree_SOURCES = src/ostree/main.c \
        src/ostree/ot-builtins.h \
+       src/ostree/ot-builtin-admin.c \
        src/ostree/ot-builtin-cat.c \
        src/ostree/ot-builtin-config.c \
        src/ostree/ot-builtin-checkout.c \
@@ -45,6 +46,16 @@ ostree_SOURCES = src/ostree/main.c \
        src/ostree/ot-main.c \
        $(NULL)
 
+# Admin subcommand
+ostree_SOURCES += \
+       src/ostree/ot-admin-builtin-init.c \
+       src/ostree/ot-admin-builtin-diff.c \
+       src/ostree/ot-admin-builtin-deploy.c \
+       src/ostree/ot-admin-builtin-update-kernel.c \
+       src/ostree/ot-admin-functions.h \
+       src/ostree/ot-admin-functions.c \
+       $(NULL)
+
 ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libgsystem -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -I$(srcdir)/src/ostree  -DLOCALEDIR=\"$(datadir)/locale\"
 ostree_bin_shared_ldadd = libotutil.la libostree.la
 
@@ -64,3 +75,16 @@ ostree_pull_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_SOUP_LIBS)
 endif
 
 MANPAGES += doc/ostree.1
+
+if ENABLE_KERNEL_UPDATES
+
+grub2dir = $(sysconfdir)/grub.d
+grub2_SCRIPTS = src/ostree/grub2/15_ostree
+
+kernelpostinstdir = $(sysconfdir)/kernel/postinst.d
+kernelpostinst_SCRIPTS = src/ostree/kernel/15_ostree_update
+
+kernelprermdir = $(sysconfdir)/kernel/prerm.d
+kernelprerm_SCRIPTS = src/ostree/kernel/15_ostree_remove
+
+endif
index b8a99b496c77dc94876fd640ab700d4ec351d8ab..55b04b1863f7863ba1418934f126c0b5c33998a2 100644 (file)
@@ -78,7 +78,6 @@ include Makefile-daemon.am
 include Makefile-otutil.am
 include Makefile-libostree.am
 include Makefile-ostree.am
-include Makefile-ostadmin.am
 include Makefile-switchroot.am
 include Makefile-triggers.am
 
diff --git a/src/ostadmin/grub2/15_ostree b/src/ostadmin/grub2/15_ostree
deleted file mode 100755 (executable)
index 6f9d51b..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-#! /bin/sh
-set -e
-
-# grub-mkconfig helper script.
-# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
-#
-# GRUB is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# GRUB is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
-
-prefix="/usr"
-exec_prefix="/usr"
-datarootdir="${prefix}/share"
-
-. "/usr/share/grub/grub-mkconfig_lib"
-
-export TEXTDOMAIN=grub
-export TEXTDOMAINDIR="${datarootdir}/locale"
-
-CLASS="--class gnu-linux --class gnu --class os --class ostree"
-OS="GNOME OS (Ostree)"
-
-# loop-AES arranges things so that /dev/loop/X can be our root device, but
-# the initrds that Linux uses don't like that.
-case ${GRUB_DEVICE} in
-  /dev/loop/*|/dev/loop[0-9])
-    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
-  ;;
-esac
-
-if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
-    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
-    || uses_abstraction "${GRUB_DEVICE}" lvm; then
-  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
-else
-  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
-fi
-
-GRUBFS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`"
-
-if [ x"$GRUBFS" = x ]; then
-    GRUBFS="$(stat -f --printf=%T / || true)"
-fi
-
-case x"$GRUBFS" in
-    xbtrfs)
-       rootsubvol="`make_system_path_relative_to_its_root /`"
-       rootsubvol="${rootsubvol#/}"
-       if [ "x${rootsubvol}" != x ]; then
-           GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
-       fi;;
-    xzfs)
-       rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
-       bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`"
-       LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs}"
-       ;;
-esac
-
-title_correction_code=
-
-linux_entry ()
-{
-  os="$1"
-  version="$2"
-  type="$3"
-  args="$4"
-
-  if [ -z "$boot_device_id" ]; then
-      boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
-  fi
-  if [ x$type != xsimple ] ; then
-      case $type in
-         recovery)
-             title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
-         *)
-             title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
-      esac
-      if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
-         replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
-         quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
-         title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
-         grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
-      fi
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
-  else
-      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
-  fi      
-  if [ x$type != xrecovery ] ; then
-      save_default_entry | sed -e "s/^/\t/"
-  fi
-
-  # Use ELILO's generic "efifb" when it's known to be available.
-  # FIXME: We need an interface to select vesafb in case efifb can't be used.
-  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
-      echo "   load_video" | sed "s/^/$submenu_indentation/"
-      if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \
-         && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
-         echo "        set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
-      fi
-  else
-      if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
-         echo "        load_video" | sed "s/^/$submenu_indentation/"
-      fi
-      echo "   set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
-  fi
-
-  echo "       insmod gzio" | sed "s/^/$submenu_indentation/"
-
-  if [ x$dirname = x/ ]; then
-    if [ -z "${prepare_root_cache}" ]; then
-      prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/")"
-    fi
-    printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
-  else
-    if [ -z "${prepare_boot_cache}" ]; then
-      prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
-    fi
-    printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
-  fi
-  message="$(gettext_printf "Loading Linux %s ..." ${version})"
-  sed "s/^/$submenu_indentation/" << EOF
-       echo    '$message'
-       linux   ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
-EOF
-  if test -n "${initrd}" ; then
-    # TRANSLATORS: ramdisk isn't identifier. Should be translated.
-    message="$(gettext_printf "Loading initial ramdisk ...")"
-    sed "s/^/$submenu_indentation/" << EOF
-       echo    '$message'
-       initrd  ${rel_dirname}/${initrd}
-EOF
-  fi
-  sed "s/^/$submenu_indentation/" << EOF
-}
-EOF
-}
-
-machine=`uname -m`
-case "x$machine" in
-    xi?86 | xx86_64)
-       list=`for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do
-                  if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
-              done` ;;
-    *) 
-       list=`for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do
-                  if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
-            done` ;;
-esac
-
-case "$machine" in
-    i?86) GENKERNEL_ARCH="x86" ;;
-    mips|mips64) GENKERNEL_ARCH="mips" ;;
-    mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
-    arm*) GENKERNEL_ARCH="arm" ;;
-    *) GENKERNEL_ARCH="$machine" ;;
-esac
-
-prepare_boot_cache=
-prepare_root_cache=
-boot_device_id=
-title_correction_code=
-
-# Extra indentation to add to menu entries in a submenu. We're not in a submenu
-# yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
-submenu_indentation=""
-
-is_first_entry=true
-while [ "x$list" != "x" ] ; do
-  linux=`version_find_latest $list`
-  gettext_printf "Found linux image: %s\n" "$linux" >&2
-  basename=`basename $linux`
-  dirname=`dirname $linux`
-  rel_dirname=`make_system_path_relative_to_its_root $dirname`
-  version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
-  alt_version=`echo $version | sed -e "s,\.old$,,g"`
-  linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
-
-  initrd=
-  config=
-  initramfs=
-
-  for i in "initrd.img-ostree-${version}" "initrd-ostree-${version}.img" "initrd-ostree-${version}.gz" \
-          "initrd-ostree-${version}" "initramfs-ostree-${version}.img" \
-          "initrd.img-ostree-${alt_version}" "initrd-ostree-${alt_version}.img" \
-          "initrd-ostree-${alt_version}" "initramfs-ostree-${alt_version}.img"; do
-    if test -e "${dirname}/${i}" ; then
-      initrd="$i"
-      break
-    fi
-  done
-
-  config=
-  for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
-    if test -e "${i}" ; then
-      config="${i}"
-      break
-    fi
-  done
-
-  initramfs=
-  if test -n "${config}" ; then
-      initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"`
-  fi
-
-  if test -n "${initrd}" ; then
-    gettext_printf "Found initrd image: %s\n" "${dirname}/${initrd}" >&2
-  elif test -z "${initramfs}" ; then
-    # ostree can't work without initrd
-    gettext_printf "Skipping version %s (missing initrd)\n" "${version}" >&2
-    list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
-    continue
-  fi
-
-  if [ "x$is_first_entry" = xtrue ]; then
-    linux_entry "${OS}" "${version}" simple \
-    "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ostree=${GRUB_OSTREE_REVISION}"
-
-    submenu_indentation="\t"
-    
-    if [ -z "$boot_device_id" ]; then
-       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
-    fi
-    # TRANSLATORS: %s is replaced with an OS name
-    echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {"
-  fi
-
-  linux_entry "${OS}" "${version}" advanced \
-              "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ostree=${GRUB_OSTREE_REVISION}"
-  if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
-    linux_entry "${OS}" "${version}" recovery \
-                "single ${GRUB_CMDLINE_LINUX} ostree=${GRUB_OSTREE_REVISION}"
-  fi
-
-  list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
-  is_first_entry=false
-done
-
-# If at least one kernel was found, then we need to
-# add a closing '}' for the submenu command.
-if [ x"$is_first_entry" != xtrue ]; then
-  echo '}'
-fi
-
-echo "$title_correction_code"
diff --git a/src/ostadmin/kernel/15_ostree_remove b/src/ostadmin/kernel/15_ostree_remove
deleted file mode 100755 (executable)
index 53b2a6e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-version=$1
-
-if [ -z "$version" ]; then
-    echo "$0: kernel version required"
-    exit 1
-fi
-
-rm -fR "/ostree/modules/${version}"
-rm -fR "/boot/initramfs-ostree-${version}.img"
diff --git a/src/ostadmin/kernel/15_ostree_update b/src/ostadmin/kernel/15_ostree_update
deleted file mode 100755 (executable)
index 4cdac1c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-version=$1
-
-if [ -z "$version" ]; then
-    echo "$0: kernel version required"
-    exit 1
-fi
-
-ostadmin update-kernel current/ ${version}
diff --git a/src/ostadmin/main.c b/src/ostadmin/main.c
deleted file mode 100644 (file)
index ca061f7..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include <gio/gio.h>
-
-#include <string.h>
-
-#include "ot-admin-main.h"
-#include "ot-admin-builtins.h"
-
-static OtAdminBuiltin builtins[] = {
-  { "deploy", ot_admin_builtin_deploy, 0 },
-  { "diff", ot_admin_builtin_diff, 0 },
-  { "init", ot_admin_builtin_init, 0 },
-  { "update-kernel", ot_admin_builtin_update_kernel, 0 },
-  { NULL }
-};
-
-int
-main (int    argc,
-      char **argv)
-{
-  return ot_admin_main (argc, argv, builtins);
-}
diff --git a/src/ostadmin/ot-admin-builtin-deploy.c b/src/ostadmin/ot-admin-builtin-deploy.c
deleted file mode 100644 (file)
index 6322f2c..0000000
+++ /dev/null
@@ -1,583 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ot-admin-builtins.h"
-#include "ot-admin-functions.h"
-#include "ostree.h"
-
-#include <glib/gi18n.h>
-
-typedef struct {
-  OstreeRepo  *repo;
-  GFile *ostree_dir;
-} OtAdminDeploy;
-
-static gboolean opt_no_kernel;
-static gboolean opt_force;
-static char *opt_ostree_dir = "/ostree";
-
-static GOptionEntry options[] = {
-  { "ostree-dir", 0, 0, G_OPTION_ARG_STRING, &opt_ostree_dir, "Path to OSTree root directory (default: /ostree)", NULL },
-  { "no-kernel", 0, 0, G_OPTION_ARG_NONE, &opt_no_kernel, "Don't update kernel related config (initramfs, bootloader)", NULL },
-  { "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Overwrite any existing deployment", NULL },
-  { NULL }
-};
-
-/**
- * update_current:
- *
- * Atomically swap the /ostree/current symbolic link to point to a new
- * path.  If successful, the old current will be saved as
- * /ostree/previous.
- *
- * Unless the new-current equals current, in which case, do nothing.
- */
-static gboolean
-update_current (OtAdminDeploy      *self,
-                GFile              *current_deployment,
-                GFile              *deploy_target,
-                GCancellable       *cancellable,
-                GError            **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *current_path = NULL;
-  ot_lobj GFile *previous_path = NULL;
-  ot_lobj GFile *tmp_current_path = NULL;
-  ot_lobj GFile *tmp_previous_path = NULL;
-  ot_lobj GFileInfo *previous_info = NULL;
-  ot_lfree char *relative_current = NULL;
-  ot_lfree char *relative_previous = NULL;
-
-  current_path = g_file_get_child (self->ostree_dir, "current");
-  previous_path = g_file_get_child (self->ostree_dir, "previous");
-
-  relative_current = g_file_get_relative_path (self->ostree_dir, deploy_target);
-  g_assert (relative_current);
-
-  if (current_deployment)
-    {
-      ot_lfree char *relative_previous = NULL;
-
-      if (g_file_equal (current_deployment, deploy_target))
-        {
-          g_print ("ostadmin: %s already points to %s\n", ot_gfile_get_path_cached (current_path),
-                   relative_current);
-          return TRUE;
-        }
-
-      tmp_previous_path = g_file_get_child (self->ostree_dir, "tmp-previous");
-      (void) ot_gfile_unlink (tmp_previous_path, NULL, NULL);
-
-      relative_previous = g_file_get_relative_path (self->ostree_dir, current_deployment);
-      g_assert (relative_previous);
-      if (symlink (relative_previous, ot_gfile_get_path_cached (tmp_previous_path)) < 0)
-        {
-          ot_util_set_error_from_errno (error, errno);
-          goto out;
-        }
-    }
-
-  tmp_current_path = g_file_get_child (self->ostree_dir, "tmp-current");
-  (void) ot_gfile_unlink (tmp_current_path, NULL, NULL);
-
-  if (symlink (relative_current, ot_gfile_get_path_cached (tmp_current_path)) < 0)
-    {
-      ot_util_set_error_from_errno (error, errno);
-      goto out;
-    }
-
-  if (!ot_gfile_rename (tmp_current_path, current_path,
-                        cancellable, error))
-    goto out;
-
-  if (tmp_previous_path)
-    {
-      if (!ot_gfile_rename (tmp_previous_path, previous_path,
-                            cancellable, error))
-        goto out;
-    }
-
-  g_print ("ostadmin: %s set to %s\n", ot_gfile_get_path_cached (current_path),
-           relative_current);
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-typedef struct {
-  GError **error;
-  gboolean caught_error;
-
-  GMainLoop *loop;
-} ProcessOneCheckoutData;
-
-static void
-on_checkout_complete (GObject         *object,
-                      GAsyncResult    *result,
-                      gpointer         user_data)
-{
-  ProcessOneCheckoutData *data = user_data;
-  GError *local_error = NULL;
-
-  if (!ostree_repo_checkout_tree_finish ((OstreeRepo*)object, result,
-                                         &local_error))
-    goto out;
-
- out:
-  if (local_error)
-    {
-      data->caught_error = TRUE;
-      g_propagate_error (data->error, local_error);
-    }
-  g_main_loop_quit (data->loop);
-}
-
-
-/**
- * ensure_unlinked:
- *
- * Like ot_gfile_unlink(), but return successfully if the file doesn't
- * exist.
- */
-static gboolean
-ensure_unlinked (GFile         *path,
-                 GCancellable  *cancellable,
-                 GError       **error)
-{
-  gboolean ret = FALSE;
-  GError *temp_error = NULL;
-
-  if (!ot_gfile_unlink (path, cancellable, &temp_error))
-    {
-      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-        {
-          g_clear_error (&temp_error);
-        }
-      else
-        {
-          g_propagate_error (error, temp_error);
-          goto out;
-        }
-    }
-  
-  ret = TRUE;
- out:
-  return ret;
-}
-
-/**
- * copy_one_config_file:
- *
- * Copy @file from @modified_etc to @new_etc, overwriting any existing
- * file there.
- */
-static gboolean
-copy_one_config_file (OtAdminDeploy      *self,
-                      GFile              *modified_etc,
-                      GFile              *new_etc,
-                      GFile              *file,
-                      GCancellable       *cancellable,
-                      GError            **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *target_file = NULL;
-  ot_lobj GFile *target_parent = NULL;
-  ot_lfree char *path = NULL;
-
-  path = g_file_get_relative_path (modified_etc, file);
-  g_assert (path);
-  target_file = g_file_resolve_relative_path (new_etc, path);
-  target_parent = g_file_get_parent (target_file);
-
-  /* FIXME actually we need to copy permissions and xattrs */
-  if (!ot_gfile_ensure_directory (target_parent, TRUE, error))
-    goto out;
-
-  if (!g_file_copy (file, target_file, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA,
-                    cancellable, NULL, NULL, error))
-    goto out;
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-/**
- * merge_etc_changes:
- *
- * Compute the difference between @orig_etc and @modified_etc,
- * and apply that to @new_etc.
- *
- * The algorithm for computing the difference is pretty simple; it's
- * approximately equivalent to "diff -unR orig_etc modified_etc",
- * except that rather than attempting a 3-way merge if a file is also
- * changed in @new_etc, the modified version always wins.
- */
-static gboolean
-merge_etc_changes (OtAdminDeploy  *self,
-                   GFile          *orig_etc,
-                   GFile          *modified_etc,
-                   GFile          *new_etc,
-                   GCancellable   *cancellable,
-                   GError        **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *ostree_etc = NULL;
-  ot_lobj GFile *tmp_etc = NULL;
-  ot_lptrarray GPtrArray *modified = NULL;
-  ot_lptrarray GPtrArray *removed = NULL;
-  ot_lptrarray GPtrArray *added = NULL;
-  guint i;
-
-  modified = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-  removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-  added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-
-  if (!ostree_diff_dirs (orig_etc, modified_etc, modified, removed, added,
-                         cancellable, error))
-    {
-      g_prefix_error (error, "While computing configuration diff: ");
-      goto out;
-    }
-
-  if (modified->len > 0 || removed->len > 0 || added->len > 0)
-    g_print ("ostadmin: Processing config: %u modified, %u removed, %u added\n", 
-             modified->len,
-             removed->len,
-             added->len);
-  else
-    g_print ("ostadmin: No modified configuration\n");
-
-  for (i = 0; i < removed->len; i++)
-    {
-      GFile *file = removed->pdata[i];
-      ot_lobj GFile *target_file = NULL;
-      ot_lfree char *path = NULL;
-
-      path = g_file_get_relative_path (orig_etc, file);
-      g_assert (path);
-      target_file = g_file_resolve_relative_path (new_etc, path);
-
-      if (!ensure_unlinked (target_file, cancellable, error))
-        goto out;
-    }
-
-  for (i = 0; i < modified->len; i++)
-    {
-      OstreeDiffItem *diff = modified->pdata[i];
-      if (!copy_one_config_file (self, modified_etc, new_etc, diff->src,
-                                 cancellable, error))
-        goto out;
-    }
-  for (i = 0; i < added->len; i++)
-    {
-      GFile *file = added->pdata[i];
-      if (!copy_one_config_file (self, modified_etc, new_etc, file,
-                                 cancellable, error))
-        goto out;
-    }
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-/**
- * deploy_tree:
- *
- * Look up @revision in the repository, and check it out in
- * OSTREE_DIR/deploy/DEPLOY_TARGET.
- *
- * Merge configuration changes from the old deployment, if any.
- *
- * Update the OSTREE_DIR/current and OSTREE_DIR/previous symbolic
- * links.
- */
-static gboolean
-deploy_tree (OtAdminDeploy     *self,
-             const char        *deploy_target,
-             const char        *revision,
-             GFile            **out_deploy_dir,           
-             GCancellable      *cancellable,
-             GError           **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *deploy_dir = NULL;
-  ot_lfree char *deploy_target_fullname = NULL;
-  ot_lfree char *deploy_target_fullname_tmp = NULL;
-  ot_lobj GFile *deploy_target_path = NULL;
-  ot_lobj GFile *deploy_target_path_tmp = NULL;
-  ot_lfree char *deploy_target_etc_name = NULL;
-  ot_lobj GFile *deploy_target_etc_path = NULL;
-  ot_lobj GFile *deploy_target_default_etc_path = NULL;
-  ot_lobj GFile *deploy_parent = NULL;
-  ot_lobj GFile *previous_deployment = NULL;
-  ot_lobj GFile *previous_deployment_etc = NULL;
-  ot_lobj GFile *previous_deployment_etc_default = NULL;
-  ot_lobj OstreeRepoFile *root = NULL;
-  ot_lobj GFileInfo *file_info = NULL;
-  ot_lobj GFileInfo *existing_checkout_info = NULL;
-  ot_lfree char *checkout_target_name = NULL;
-  ot_lfree char *checkout_target_tmp_name = NULL;
-  ot_lfree char *resolved_commit = NULL;
-  GError *temp_error = NULL;
-  gboolean skip_checkout;
-
-  if (!revision)
-    revision = deploy_target;
-
-  deploy_dir = g_file_get_child (self->ostree_dir, "deploy");
-
-  if (!ostree_repo_resolve_rev (self->repo, revision, FALSE, &resolved_commit, error))
-    goto out;
-
-  root = (OstreeRepoFile*)ostree_repo_file_new_root (self->repo, resolved_commit);
-  if (!ostree_repo_file_ensure_resolved (root, error))
-    goto out;
-
-  file_info = g_file_query_info ((GFile*)root, OSTREE_GIO_FAST_QUERYINFO,
-                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                 cancellable, error);
-  if (!file_info)
-    goto out;
-
-  deploy_target_fullname = g_strconcat (deploy_target, "-", resolved_commit, NULL);
-  deploy_target_path = g_file_resolve_relative_path (deploy_dir, deploy_target_fullname);
-
-  deploy_target_fullname_tmp = g_strconcat (deploy_target_fullname, ".tmp", NULL);
-  deploy_target_path_tmp = g_file_resolve_relative_path (deploy_dir, deploy_target_fullname_tmp);
-
-  deploy_parent = g_file_get_parent (deploy_target_path);
-  if (!ot_gfile_ensure_directory (deploy_parent, TRUE, error))
-    goto out;
-
-  deploy_target_etc_name = g_strconcat (deploy_target, "-", resolved_commit, "-etc", NULL);
-  deploy_target_etc_path = g_file_resolve_relative_path (deploy_dir, deploy_target_etc_name);
-
-  /* Delete any previous temporary data */
-  if (!ot_gio_shutil_rm_rf (deploy_target_path_tmp, cancellable, error))
-    goto out;
-
-  existing_checkout_info = g_file_query_info (deploy_target_path, OSTREE_GIO_FAST_QUERYINFO,
-                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                              cancellable, &temp_error);
-  if (existing_checkout_info)
-    {
-      if (opt_force)
-        {
-          if (!ot_gio_shutil_rm_rf (deploy_target_path, cancellable, error))
-            goto out;
-          if (!ot_gio_shutil_rm_rf (deploy_target_etc_path, cancellable, error))
-            goto out;
-          
-          skip_checkout = FALSE;
-        }
-      else
-        skip_checkout = TRUE;
-    }
-  else if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-    {
-      g_clear_error (&temp_error);
-      skip_checkout = FALSE;
-    }
-  else
-    {
-      g_propagate_error (error, temp_error);
-      goto out;
-    }
-
-  if (!ot_admin_get_current_deployment (self->ostree_dir, &previous_deployment,
-                                        cancellable, error))
-    goto out;
-  if (previous_deployment)
-    {
-      ot_lfree char *etc_name;
-      ot_lobj GFile *parent;
-
-      etc_name = g_strconcat (ot_gfile_get_basename_cached (previous_deployment), "-etc", NULL);
-      parent = g_file_get_parent (previous_deployment);
-
-      previous_deployment_etc = g_file_get_child (parent, etc_name);
-
-      if (!g_file_query_exists (previous_deployment_etc, cancellable)
-          || g_file_equal (previous_deployment, deploy_target_path))
-        g_clear_object (&previous_deployment_etc);
-      else
-        previous_deployment_etc_default = g_file_get_child (previous_deployment, "etc");
-    }
-
-
-  if (!skip_checkout)
-    {
-      ProcessOneCheckoutData checkout_data;
-
-      g_print ("ostadmin: Creating deployment %s\n",
-               ot_gfile_get_path_cached (deploy_target_path));
-
-      memset (&checkout_data, 0, sizeof (checkout_data));
-      checkout_data.loop = g_main_loop_new (NULL, TRUE);
-      checkout_data.error = error;
-
-      ostree_repo_checkout_tree_async (self->repo, 0, 0, deploy_target_path_tmp, root,
-                                       file_info, cancellable,
-                                       on_checkout_complete, &checkout_data);
-
-      g_main_loop_run (checkout_data.loop);
-
-      g_main_loop_unref (checkout_data.loop);
-
-      if (checkout_data.caught_error)
-        goto out;
-
-      if (!ostree_run_triggers_in_root (deploy_target_path_tmp, cancellable, error))
-        goto out;
-
-      deploy_target_default_etc_path = ot_gfile_get_child_strconcat (deploy_target_path_tmp, "etc", NULL);
-
-      if (!ot_gio_shutil_rm_rf (deploy_target_etc_path, cancellable, error))
-        goto out;
-
-      if (!ot_gio_shutil_cp_a (deploy_target_default_etc_path, deploy_target_etc_path,
-                               cancellable, error))
-        goto out;
-
-      g_print ("ostadmin: Created %s\n", ot_gfile_get_path_cached (deploy_target_etc_path));
-
-      if (previous_deployment_etc)
-        {
-          if (!merge_etc_changes (self, previous_deployment_etc_default,
-                                  previous_deployment_etc, deploy_target_etc_path, 
-                                  cancellable, error))
-            goto out;
-        }
-      else
-        g_print ("ostadmin: No previous deployment; therefore, no configuration changes to merge\n");
-
-      if (!ot_gfile_rename (deploy_target_path_tmp, deploy_target_path,
-                            cancellable, error))
-        goto out;
-    }
-
-  if (!update_current (self, previous_deployment, deploy_target_path,
-                       cancellable, error))
-    goto out;
-
-  ret = TRUE;
-  ot_transfer_out_value (out_deploy_dir, &deploy_target_path);
- out:
-  return ret;
-}
-
-/**
- * do_update_kernel:
- *
- * Ensure we have a GRUB entry, initramfs set up, etc.
- */
-static gboolean
-do_update_kernel (OtAdminDeploy     *self,
-                  GFile             *deploy_path,
-                  GCancellable      *cancellable,
-                  GError           **error)
-{
-  gboolean ret = FALSE;
-  ot_lptrarray GPtrArray *args = NULL;
-
-  args = g_ptr_array_new ();
-  ot_ptrarray_add_many (args, "ostadmin", "update-kernel",
-                        "--ostree-dir", ot_gfile_get_path_cached (self->ostree_dir),
-                        ot_gfile_get_path_cached (deploy_path), NULL);
-  g_ptr_array_add (args, NULL);
-
-  if (!ot_spawn_sync_checked (ot_gfile_get_path_cached (self->ostree_dir),
-                              (char**)args->pdata, NULL, G_SPAWN_SEARCH_PATH,
-                              NULL, NULL, NULL, NULL, error))
-    goto out;
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-
-gboolean
-ot_admin_builtin_deploy (int argc, char **argv, GError **error)
-{
-  GOptionContext *context;
-  OtAdminDeploy self_data;
-  OtAdminDeploy *self = &self_data;
-  gboolean ret = FALSE;
-  ot_lobj GFile *repo_path = NULL;
-  ot_lobj GFile *deploy_path = NULL;
-  const char *deploy_target = NULL;
-  const char *revision = NULL;
-  __attribute__((unused)) GCancellable *cancellable = NULL;
-
-  memset (self, 0, sizeof (*self));
-
-  context = g_option_context_new ("NAME [REVISION] - Check out revision NAME (or REVISION as NAME)");
-
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
-    goto out;
-
-  if (argc < 2)
-    {
-      ot_util_usage_error (context, "NAME must be specified", error);
-      goto out;
-    }
-
-  self->ostree_dir = g_file_new_for_path (opt_ostree_dir);
-
-  if (!ot_admin_ensure_initialized (self->ostree_dir, cancellable, error))
-    goto out;
-
-  repo_path = g_file_get_child (self->ostree_dir, "repo");
-  self->repo = ostree_repo_new (repo_path);
-  if (!ostree_repo_check (self->repo, error))
-    goto out;
-
-  deploy_target = argv[1];
-  if (argc > 2)
-    revision = argv[2];
-
-  if (!deploy_tree (self, deploy_target, revision, &deploy_path,
-                    cancellable, error))
-    goto out;
-
-  if (!opt_no_kernel)
-    {
-      if (!do_update_kernel (self, deploy_path, cancellable, error))
-        goto out;
-    }
-
-  ret = TRUE;
- out:
-  g_clear_object (&self->repo);
-  g_clear_object (&self->ostree_dir);
-  if (context)
-    g_option_context_free (context);
-  return ret;
-}
diff --git a/src/ostadmin/ot-admin-builtin-diff.c b/src/ostadmin/ot-admin-builtin-diff.c
deleted file mode 100644 (file)
index c828f8e..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ot-admin-builtins.h"
-#include "ot-admin-functions.h"
-#include "ostree.h"
-
-#include <glib/gi18n.h>
-
-static char *opt_ostree_dir = "/ostree";
-
-static GOptionEntry options[] = {
-  { "ostree-dir", 0, 0, G_OPTION_ARG_STRING, &opt_ostree_dir, "Path to OSTree root directory (default: /ostree)", NULL },
-  { NULL }
-};
-
-gboolean
-ot_admin_builtin_diff (int argc, char **argv, GError **error)
-{
-  GOptionContext *context;
-  gboolean ret = FALSE;
-  ot_lobj GFile *ostree_dir = NULL;
-  ot_lobj GFile *repo_path = NULL;
-  ot_lobj GFile *deployment = NULL;
-  ot_lobj GFile *deploy_parent = NULL;
-  ot_lptrarray GPtrArray *modified = NULL;
-  ot_lptrarray GPtrArray *removed = NULL;
-  ot_lptrarray GPtrArray *added = NULL;
-  ot_lobj GFile *orig_etc_path = NULL;
-  ot_lobj GFile *new_etc_path = NULL;
-  __attribute__((unused)) GCancellable *cancellable = NULL;
-
-  context = g_option_context_new ("[NAME] - Diff configuration for revision NAME");
-
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
-    goto out;
-  
-  ostree_dir = g_file_new_for_path (opt_ostree_dir); 
-  repo_path = g_file_get_child (ostree_dir, "repo");
-
-  if (argc > 1)
-    {
-      deployment = ot_gfile_get_child_build_path (ostree_dir, "deploy", argv[1], NULL);
-      if (!g_file_query_exists (deployment, NULL))
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "Deployment %s doesn't exist", ot_gfile_get_path_cached (deployment));
-          goto out;
-        }
-    }
-  else
-    {
-      if (!ot_admin_get_current_deployment (ostree_dir, &deployment,
-                                            cancellable, error))
-        goto out;
-    }
-
-  orig_etc_path = g_file_resolve_relative_path (deployment, "etc");
-  deploy_parent = g_file_get_parent (deployment);
-  new_etc_path = ot_gfile_get_child_strconcat (deploy_parent,
-                                               ot_gfile_get_basename_cached (deployment),
-                                               "-etc", NULL);
-  
-  modified = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-  removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-  added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-  if (!ostree_diff_dirs (orig_etc_path, new_etc_path, modified, removed, added,
-                         cancellable, error))
-    goto out;
-
-  ostree_diff_print (new_etc_path, modified, removed, added);
-
-  ret = TRUE;
- out:
-  g_clear_object (&ostree_dir);
-  if (context)
-    g_option_context_free (context);
-  return ret;
-}
diff --git a/src/ostadmin/ot-admin-builtin-init.c b/src/ostadmin/ot-admin-builtin-init.c
deleted file mode 100644 (file)
index 703e14f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ot-admin-builtins.h"
-#include "ot-admin-functions.h"
-#include "otutil.h"
-
-#include <glib/gi18n.h>
-
-static char *opt_ostree_dir = "/ostree";
-
-static GOptionEntry options[] = {
-  { "ostree-dir", 0, 0, G_OPTION_ARG_STRING, &opt_ostree_dir, "Path to OSTree root directory (default: /ostree)", NULL },
-  { NULL }
-};
-
-
-gboolean
-ot_admin_builtin_init (int argc, char **argv, GError **error)
-{
-  GOptionContext *context;
-  gboolean ret = FALSE;
-  ot_lobj GFile *dir = NULL;
-  __attribute__((unused)) GCancellable *cancellable = NULL;
-
-  context = g_option_context_new ("- Initialize /ostree directory");
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
-    goto out;
-
-  dir = g_file_new_for_path (opt_ostree_dir);
-
-  if (!ot_admin_ensure_initialized (dir, cancellable, error))
-    goto out;
-
-  g_print ("%s initialized as OSTree root\n", opt_ostree_dir);
-
-  ret = TRUE;
- out:
-  if (context)
-    g_option_context_free (context);
-  return ret;
-}
diff --git a/src/ostadmin/ot-admin-builtin-update-kernel.c b/src/ostadmin/ot-admin-builtin-update-kernel.c
deleted file mode 100644 (file)
index d8edad5..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ot-admin-builtins.h"
-#include "ostree.h"
-
-#include <glib/gi18n.h>
-#include <sys/utsname.h>
-
-typedef struct {
-  OstreeRepo  *repo;
-} OtAdminUpdateKernel;
-
-static char *opt_ostree_dir = "/ostree";
-
-static GOptionEntry options[] = {
-  { "ostree-dir", 0, 0, G_OPTION_ARG_STRING, &opt_ostree_dir, "Path to OSTree root directory", NULL },
-  { NULL }
-};
-
-static gboolean
-copy_modules (const char    *release,
-              GCancellable  *cancellable,
-              GError       **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *src_modules_file = NULL;
-  ot_lobj GFile *dest_modules_parent = NULL;
-  ot_lobj GFile *dest_modules_file = NULL;
-  
-  src_modules_file = ot_gfile_from_build_path ("/lib/modules", release, NULL);
-  dest_modules_file = ot_gfile_from_build_path (opt_ostree_dir, "modules", release, NULL);
-  dest_modules_parent = g_file_get_parent (dest_modules_file);
-  if (!ot_gfile_ensure_directory (dest_modules_parent, FALSE, error))
-    goto out;
-
-  if (!g_file_query_exists (dest_modules_file, cancellable))
-    {
-      if (!ot_gio_shutil_cp_al_or_fallback (src_modules_file, dest_modules_file, cancellable, error))
-        goto out;
-    }
-      
-  ret = TRUE;
- out:
-  if (error)
-    g_prefix_error (error, "Error copying kernel modules: ");
-  return ret;
-}
-
-static gboolean
-update_initramfs (const char       *release,
-                  const char       *deploy_path,
-                  GCancellable     *cancellable,
-                  GError          **error)
-{
-  gboolean ret = FALSE;
-  ot_lfree char *initramfs_name = NULL;
-  ot_lobj GFile *initramfs_file = NULL;
-
-  initramfs_name = g_strconcat ("initramfs-ostree-", release, ".img", NULL);
-  initramfs_file = ot_gfile_from_build_path ("/boot", initramfs_name, NULL);
-  if (!g_file_query_exists (initramfs_file, NULL))
-    {
-      ot_lptrarray GPtrArray *mkinitramfs_args = NULL;
-      ot_lobj GFile *tmpdir = NULL;
-      ot_lfree char *initramfs_tmp_path = NULL;
-      ot_lfree char *ostree_vardir = NULL;
-      ot_lfree char *ostree_moduledir = NULL;
-      ot_lobj GFile *initramfs_tmp_file = NULL;
-      ot_lobj GFileInfo *initramfs_tmp_info = NULL;
-          
-      if (!ostree_create_temp_dir (NULL, "ostree-initramfs", NULL, &tmpdir,
-                                   cancellable, error))
-        goto out;
-
-      ostree_vardir = g_build_filename (opt_ostree_dir, "var", NULL);
-      ostree_moduledir = g_build_filename (opt_ostree_dir, "modules", NULL);
-
-      mkinitramfs_args = g_ptr_array_new ();
-      /* Note: the hardcoded /tmp path below is not actually a
-       * security flaw, because we've bind-mounted dracut's view
-       * of /tmp to the securely-created tmpdir above.
-       */
-      ot_ptrarray_add_many (mkinitramfs_args,
-                            "linux-user-chroot",
-                            "--mount-readonly", "/",
-                            "--mount-proc", "/proc",
-                            "--mount-bind", "/dev", "/dev",
-                            "--mount-bind", ostree_vardir, "/var",
-                            "--mount-bind", ot_gfile_get_path_cached (tmpdir), "/tmp",
-                            "--mount-bind", ostree_moduledir, "/lib/modules",
-                            deploy_path,
-                            "dracut", "-f", "/tmp/initramfs-ostree.img", release,
-                            NULL);
-      g_ptr_array_add (mkinitramfs_args, NULL);
-          
-      g_print ("Generating initramfs using %s...\n", deploy_path);
-      if (!ot_spawn_sync_checked (NULL, (char**)mkinitramfs_args->pdata, NULL,
-                                  G_SPAWN_SEARCH_PATH,
-                                  NULL, NULL, NULL, NULL, error))
-        goto out;
-          
-      initramfs_tmp_file = g_file_get_child (tmpdir, "initramfs-ostree.img");
-      initramfs_tmp_info = g_file_query_info (initramfs_tmp_file, OSTREE_GIO_FAST_QUERYINFO,
-                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                              cancellable, error);
-      if (!initramfs_tmp_info)
-        goto out;
-
-      if (g_file_info_get_size (initramfs_tmp_info) == 0)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "Initramfs generation failed, check dracut.log");
-          goto out;
-        }
-
-      if (!g_file_copy (initramfs_tmp_file, initramfs_file, 0, cancellable, NULL, NULL, error))
-        goto out;
-          
-      g_print ("Created: %s\n", ot_gfile_get_path_cached (initramfs_file));
-
-      (void) ot_gfile_unlink (initramfs_tmp_file, NULL, NULL);
-      (void) rmdir (ot_gfile_get_path_cached (tmpdir));
-    }
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-static gboolean
-grep_literal (GFile              *f,
-              const char         *string,
-              gboolean           *out_matches,
-              GCancellable       *cancellable,
-              GError            **error)
-{
-  gboolean ret = FALSE;
-  gboolean ret_matches = FALSE;
-  ot_lobj GInputStream *in = NULL;
-  ot_lobj GDataInputStream *datain = NULL;
-  ot_lfree char *line = NULL;
-
-  in = (GInputStream*)g_file_read (f, cancellable, error);
-  if (!in)
-    goto out;
-  datain = (GDataInputStream*)g_data_input_stream_new (in);
-  if (!in)
-    goto out;
-
-  while ((line = g_data_input_stream_read_line (datain, NULL, cancellable, error)) != NULL)
-    {
-      if (strstr (line, string))
-        {
-          ret_matches = TRUE;
-          break;
-        }
-      
-      g_free (line);
-    }
-
-  ret = TRUE;
-  if (out_matches)
-    *out_matches = ret_matches;
- out:
-  return ret;
-}
-
-static gboolean
-get_kernel_path_from_release (const char         *release,
-                              GFile             **out_path,
-                              GCancellable       *cancellable,
-                              GError            **error)
-{
-  gboolean ret = FALSE;
-  ot_lfree char *name = NULL;
-  ot_lobj GFile *possible_path = NULL;
-
-  /* TODO - replace this with grubby code */
-
-  name = g_strconcat ("vmlinuz-", release, NULL);
-  possible_path = ot_gfile_from_build_path ("/boot", name, NULL);
-  if (!g_file_query_exists (possible_path, cancellable))
-    g_clear_object (&possible_path);
-
-  ret = TRUE;
-  ot_transfer_out_value (out_path, &possible_path);
-  /*  out: */
-  return ret;
-}
-
-static gboolean
-update_grub (const char         *release,
-             GCancellable       *cancellable,
-             GError            **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *grub_path = g_file_new_for_path ("/boot/grub/grub.conf");
-
-  if (g_file_query_exists (grub_path, cancellable))
-    {
-      gboolean have_grub_entry;
-      if (!grep_literal (grub_path, "OSTree", &have_grub_entry,
-                         cancellable, error))
-        goto out;
-
-      if (!have_grub_entry)
-        {
-          ot_lptrarray GPtrArray *grubby_args = NULL;
-          ot_lfree char *add_kernel_arg = NULL;
-          ot_lfree char *initramfs_arg = NULL;
-          ot_lobj GFile *kernel_path = NULL;
-
-          if (!get_kernel_path_from_release (release, &kernel_path, cancellable, error))
-            goto out;
-
-          if (kernel_path == NULL)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Couldn't find kernel for release %s", release);
-              goto out;
-            }
-
-          grubby_args = g_ptr_array_new ();
-          add_kernel_arg = g_strconcat ("--add-kernel=", ot_gfile_get_path_cached (kernel_path), NULL);
-          initramfs_arg = g_strconcat ("--initrd=", "/boot/initramfs-ostree-", release, ".img", NULL);
-          ot_ptrarray_add_many (grubby_args, "grubby", "--grub", add_kernel_arg, initramfs_arg,
-                                "--copy-default", "--title=OSTree", NULL);
-          g_ptr_array_add (grubby_args, NULL);
-
-          g_print ("Adding OSTree grub entry...\n");
-          if (!ot_spawn_sync_checked (NULL, (char**)grubby_args->pdata, NULL, G_SPAWN_SEARCH_PATH,
-                                      NULL, NULL, NULL, NULL, error))
-            goto out;
-        } 
-      else
-        g_print ("Already have OSTree entry in grub config\n");
-    }
-  else
-    {
-      g_print ("/boot/grub/grub.conf not found, assuming you have GRUB 2\n");
-    }
-  
-  ret = TRUE;
- out:
-  return ret;
-}
-
-gboolean
-ot_admin_builtin_update_kernel (int argc, char **argv, GError **error)
-{
-  GOptionContext *context;
-  OtAdminUpdateKernel self_data;
-  OtAdminUpdateKernel *self = &self_data;
-  gboolean ret = FALSE;
-  const char *deploy_path = NULL;
-  struct utsname utsname;
-  const char *release;
-  __attribute__((unused)) GCancellable *cancellable = NULL;
-
-  memset (self, 0, sizeof (*self));
-
-  context = g_option_context_new ("[OSTREE_REVISION [KERNEL_RELEASE]] - Update kernel and regenerate initial ramfs");
-  g_option_context_add_main_entries (context, options, NULL);
-
-  if (!g_option_context_parse (context, &argc, &argv, error))
-    goto out;
-
-  if (argc > 1)
-    deploy_path = argv[1];
-  else
-    deploy_path = "current";
-
-  (void) uname (&utsname);
-  
-  if (strcmp (utsname.sysname, "Linux") != 0)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Unsupported machine %s", utsname.sysname);
-      goto out;
-    }
-  
-  release = utsname.release;
-  if (argc > 2)
-    release = argv[2];
-  
-  if (!copy_modules (release, cancellable, error))
-    goto out;
-  
-  if (!update_initramfs (release, deploy_path, cancellable, error))
-    goto out;
-  
-  if (!update_grub (release, cancellable, error))
-    goto out;
-
-  ret = TRUE;
- out:
-  if (context)
-    g_option_context_free (context);
-  return ret;
-}
diff --git a/src/ostadmin/ot-admin-builtins.h b/src/ostadmin/ot-admin-builtins.h
deleted file mode 100644 (file)
index 4ceca2a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef __OT_ADMIN_BUILTINS__
-#define __OT_ADMIN_BUILTINS__
-
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-gboolean ot_admin_builtin_init (int argc, char **argv, GError **error);
-gboolean ot_admin_builtin_deploy (int argc, char **argv, GError **error);
-gboolean ot_admin_builtin_diff (int argc, char **argv, GError **error);
-gboolean ot_admin_builtin_update_kernel (int argc, char **argv, GError **error);
-
-G_END_DECLS
-
-#endif
diff --git a/src/ostadmin/ot-admin-functions.c b/src/ostadmin/ot-admin-functions.c
deleted file mode 100644 (file)
index 5209685..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ot-admin-functions.h"
-#include "otutil.h"
-#include "ostree-core.h"
-
-gboolean
-ot_admin_ensure_initialized (GFile         *ostree_dir,
-                             GCancellable  *cancellable,
-                             GError       **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *dir = NULL;
-
-  g_clear_object (&dir);
-  dir = g_file_get_child (ostree_dir, "repo");
-  if (!ot_gfile_ensure_directory (dir, TRUE, error))
-    goto out;
-
-  g_clear_object (&dir);
-  dir = g_file_get_child (ostree_dir, "deploy");
-  if (!ot_gfile_ensure_directory (dir, TRUE, error))
-    goto out;
-
-  g_clear_object (&dir);
-  dir = g_file_get_child (ostree_dir, "modules");
-  if (!ot_gfile_ensure_directory (dir, TRUE, error))
-    goto out;
-
-  g_clear_object (&dir);
-  dir = ot_gfile_get_child_build_path (ostree_dir, "repo", "objects", NULL);
-  if (!g_file_query_exists (dir, NULL))
-    {
-      ot_lfree char *opt_repo_arg = g_strdup_printf ("--repo=%s/repo",
-                                                      ot_gfile_get_path_cached (ostree_dir));
-      const char *child_argv[] = { "ostree", opt_repo_arg, "init", NULL };
-
-      if (!ot_spawn_sync_checked (NULL, (char**)child_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
-                                  NULL, NULL, error))
-        {
-          g_prefix_error (error, "Failed to initialize repository: ");
-          goto out;
-        }
-    }
-
-  /* Ensure a few subdirectories of /var exist, since we need them for
-     dracut generation */
-  g_clear_object (&dir);
-  dir = ot_gfile_get_child_build_path (ostree_dir, "var", "log", NULL);
-  if (!ot_gfile_ensure_directory (dir, TRUE, error))
-    goto out;
-  g_clear_object (&dir);
-  dir = ot_gfile_get_child_build_path (ostree_dir, "var", "tmp", NULL);
-  if (!ot_gfile_ensure_directory (dir, TRUE, error))
-    goto out;
-  if (chmod (ot_gfile_get_path_cached (dir), 01777) < 0)
-    {
-      ot_util_set_error_from_errno (error, errno);
-      goto out;
-    }
-
-  ret = TRUE;
- out:
-  return ret;
-}
-
-/**
- * ot_admin_get_current_deployment:
- * 
- * Returns in @out_deployment the full file path of the current
- * deployment that the /ostree/current symbolic link points to, or
- * %NULL if none.
- */
-gboolean
-ot_admin_get_current_deployment (GFile           *ostree_dir,
-                                 GFile          **out_deployment,
-                                 GCancellable    *cancellable,
-                                 GError         **error)
-{
-  gboolean ret = FALSE;
-  ot_lobj GFile *current_path = NULL;
-  ot_lobj GFileInfo *file_info = NULL;
-  ot_lobj GFile *ret_deployment = NULL;
-  GError *temp_error = NULL;
-
-  current_path = g_file_get_child (ostree_dir, "current");
-
-  file_info = g_file_query_info (current_path, OSTREE_GIO_FAST_QUERYINFO,
-                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                 cancellable, &temp_error);
-  if (!file_info)
-    {
-      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-        {
-          g_clear_error (&temp_error);
-        }
-      else
-        {
-          g_propagate_error (error, temp_error);
-          goto out;
-        }
-    }
-  else
-    {
-      const char *target;
-      if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_SYMBOLIC_LINK)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                       "Not a symbolic link");
-          goto out;
-        }
-      target = g_file_info_get_symlink_target (file_info);
-      g_assert (target);
-      ret_deployment = g_file_resolve_relative_path (ostree_dir, target);
-    }
-
-  ret = TRUE;
-  ot_transfer_out_value (out_deployment, &ret_deployment);
- out:
-  return ret;
-}
-
diff --git a/src/ostadmin/ot-admin-functions.h b/src/ostadmin/ot-admin-functions.h
deleted file mode 100644 (file)
index f4e1b74..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef __OT_ADMIN_FUNCTIONS__
-#define __OT_ADMIN_FUNCTIONS__
-
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-gboolean ot_admin_ensure_initialized (GFile         *ostree_dir, 
-                                     GCancellable  *cancellable,
-                                     GError       **error);
-
-gboolean ot_admin_get_current_deployment (GFile           *ostree_dir,
-                                          GFile          **out_deployment,
-                                          GCancellable    *cancellable,
-                                          GError         **error);
-
-G_END_DECLS
-
-#endif
diff --git a/src/ostadmin/ot-admin-main.c b/src/ostadmin/ot-admin-main.c
deleted file mode 100644 (file)
index 6052d90..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include <gio/gio.h>
-
-#include <string.h>
-
-#include "ot-admin-main.h"
-#include "otutil.h"
-
-static int
-usage (char **argv, OtAdminBuiltin *builtins, gboolean is_error)
-{
-  OtAdminBuiltin *builtin = builtins;
-  void (*print_func) (const gchar *format, ...);
-
-  if (is_error)
-    print_func = g_printerr;
-  else
-    print_func = g_print;
-
-  print_func ("usage: %s COMMAND [options]\n",
-              argv[0]);
-  print_func ("Builtin commands:\n");
-
-  while (builtin->name)
-    {
-      print_func ("  %s\n", builtin->name);
-      builtin++;
-    }
-  return (is_error ? 1 : 0);
-}
-
-static void
-prep_builtin_argv (const char *builtin,
-                   int argc,
-                   char **argv,
-                   int *out_argc,
-                   char ***out_argv)
-{
-  int i;
-  char **cmd_argv;
-
-  /* Should be argc - 1 + 1, to account for
-     the first argument (removed) and for NULL pointer */
-  cmd_argv = g_new0 (char *, argc);
-
-  for (i = 0; i < argc-1; i++)
-    cmd_argv[i] = argv[i+1];
-  cmd_argv[i] = NULL;
-  *out_argc = argc-1;
-  *out_argv = cmd_argv;
-}
-
-static void
-set_error_print_usage (GError **error, OtAdminBuiltin *builtins, const char *msg, char **argv)
-{
-  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg);
-  usage (argv, builtins, TRUE);
-}
-
-int
-ot_admin_main (int    argc,
-               char **argv,
-               OtAdminBuiltin  *builtins)
-{
-  OtAdminBuiltin *builtin;
-  GError *error = NULL;
-  int cmd_argc;
-  char **cmd_argv = NULL;
-  const char *cmd = NULL;
-
-  /* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
-  g_setenv ("GIO_USE_VFS", "local", TRUE);
-
-  g_type_init ();
-
-  g_set_prgname (argv[0]);
-
-  if (argc < 2)
-    return usage (argv, builtins, 1);
-
-  if (geteuid () != 0)
-    {
-      g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "ostadmin: Can only be run as root");
-      goto out;
-    }
-
-  cmd = argv[1];
-
-  builtin = builtins;
-  while (builtin->name)
-    {
-      if (g_strcmp0 (cmd, builtin->name) == 0)
-        break;
-      builtin++;
-    }
-
-  if (!builtin->name)
-    {
-      set_error_print_usage (&error, builtins, "Unknown command", argv);
-      goto out;
-    }
-
-  prep_builtin_argv (cmd, argc, argv, &cmd_argc, &cmd_argv);
-
-  if (!builtin->fn (cmd_argc, cmd_argv, &error))
-    goto out;
-
- out:
-  g_free (cmd_argv);
-  if (error)
-    {
-      g_printerr ("%s\n", error->message);
-      g_clear_error (&error);
-      return 1;
-    }
-  return 0;
-}
diff --git a/src/ostadmin/ot-admin-main.h b/src/ostadmin/ot-admin-main.h
deleted file mode 100644 (file)
index 8f0e637..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include <gio/gio.h>
-
-typedef struct {
-  const char *name;
-  gboolean (*fn) (int argc, char **argv, GError **error);
-  int flags;
-} OtAdminBuiltin;
-
-int ot_admin_main (int    argc, char **argv, OtAdminBuiltin  *builtins);
-
diff --git a/src/ostree/grub2/15_ostree b/src/ostree/grub2/15_ostree
new file mode 100755 (executable)
index 0000000..6f9d51b
--- /dev/null
@@ -0,0 +1,253 @@
+#! /bin/sh
+set -e
+
+# grub-mkconfig helper script.
+# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+
+prefix="/usr"
+exec_prefix="/usr"
+datarootdir="${prefix}/share"
+
+. "/usr/share/grub/grub-mkconfig_lib"
+
+export TEXTDOMAIN=grub
+export TEXTDOMAINDIR="${datarootdir}/locale"
+
+CLASS="--class gnu-linux --class gnu --class os --class ostree"
+OS="GNOME OS (Ostree)"
+
+# loop-AES arranges things so that /dev/loop/X can be our root device, but
+# the initrds that Linux uses don't like that.
+case ${GRUB_DEVICE} in
+  /dev/loop/*|/dev/loop[0-9])
+    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
+  ;;
+esac
+
+if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
+    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
+    || uses_abstraction "${GRUB_DEVICE}" lvm; then
+  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
+else
+  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
+fi
+
+GRUBFS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`"
+
+if [ x"$GRUBFS" = x ]; then
+    GRUBFS="$(stat -f --printf=%T / || true)"
+fi
+
+case x"$GRUBFS" in
+    xbtrfs)
+       rootsubvol="`make_system_path_relative_to_its_root /`"
+       rootsubvol="${rootsubvol#/}"
+       if [ "x${rootsubvol}" != x ]; then
+           GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
+       fi;;
+    xzfs)
+       rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
+       bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`"
+       LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs}"
+       ;;
+esac
+
+title_correction_code=
+
+linux_entry ()
+{
+  os="$1"
+  version="$2"
+  type="$3"
+  args="$4"
+
+  if [ -z "$boot_device_id" ]; then
+      boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+  fi
+  if [ x$type != xsimple ] ; then
+      case $type in
+         recovery)
+             title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
+         *)
+             title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+      esac
+      if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
+         replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
+         quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
+         title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
+         grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
+      fi
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+  else
+      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+  fi      
+  if [ x$type != xrecovery ] ; then
+      save_default_entry | sed -e "s/^/\t/"
+  fi
+
+  # Use ELILO's generic "efifb" when it's known to be available.
+  # FIXME: We need an interface to select vesafb in case efifb can't be used.
+  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
+      echo "   load_video" | sed "s/^/$submenu_indentation/"
+      if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \
+         && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
+         echo "        set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
+      fi
+  else
+      if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
+         echo "        load_video" | sed "s/^/$submenu_indentation/"
+      fi
+      echo "   set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
+  fi
+
+  echo "       insmod gzio" | sed "s/^/$submenu_indentation/"
+
+  if [ x$dirname = x/ ]; then
+    if [ -z "${prepare_root_cache}" ]; then
+      prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/")"
+    fi
+    printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
+  else
+    if [ -z "${prepare_boot_cache}" ]; then
+      prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
+    fi
+    printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+  fi
+  message="$(gettext_printf "Loading Linux %s ..." ${version})"
+  sed "s/^/$submenu_indentation/" << EOF
+       echo    '$message'
+       linux   ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
+EOF
+  if test -n "${initrd}" ; then
+    # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+    message="$(gettext_printf "Loading initial ramdisk ...")"
+    sed "s/^/$submenu_indentation/" << EOF
+       echo    '$message'
+       initrd  ${rel_dirname}/${initrd}
+EOF
+  fi
+  sed "s/^/$submenu_indentation/" << EOF
+}
+EOF
+}
+
+machine=`uname -m`
+case "x$machine" in
+    xi?86 | xx86_64)
+       list=`for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do
+                  if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+              done` ;;
+    *) 
+       list=`for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do
+                  if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+            done` ;;
+esac
+
+case "$machine" in
+    i?86) GENKERNEL_ARCH="x86" ;;
+    mips|mips64) GENKERNEL_ARCH="mips" ;;
+    mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
+    arm*) GENKERNEL_ARCH="arm" ;;
+    *) GENKERNEL_ARCH="$machine" ;;
+esac
+
+prepare_boot_cache=
+prepare_root_cache=
+boot_device_id=
+title_correction_code=
+
+# Extra indentation to add to menu entries in a submenu. We're not in a submenu
+# yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
+submenu_indentation=""
+
+is_first_entry=true
+while [ "x$list" != "x" ] ; do
+  linux=`version_find_latest $list`
+  gettext_printf "Found linux image: %s\n" "$linux" >&2
+  basename=`basename $linux`
+  dirname=`dirname $linux`
+  rel_dirname=`make_system_path_relative_to_its_root $dirname`
+  version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
+  alt_version=`echo $version | sed -e "s,\.old$,,g"`
+  linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
+
+  initrd=
+  config=
+  initramfs=
+
+  for i in "initrd.img-ostree-${version}" "initrd-ostree-${version}.img" "initrd-ostree-${version}.gz" \
+          "initrd-ostree-${version}" "initramfs-ostree-${version}.img" \
+          "initrd.img-ostree-${alt_version}" "initrd-ostree-${alt_version}.img" \
+          "initrd-ostree-${alt_version}" "initramfs-ostree-${alt_version}.img"; do
+    if test -e "${dirname}/${i}" ; then
+      initrd="$i"
+      break
+    fi
+  done
+
+  config=
+  for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
+    if test -e "${i}" ; then
+      config="${i}"
+      break
+    fi
+  done
+
+  initramfs=
+  if test -n "${config}" ; then
+      initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"`
+  fi
+
+  if test -n "${initrd}" ; then
+    gettext_printf "Found initrd image: %s\n" "${dirname}/${initrd}" >&2
+  elif test -z "${initramfs}" ; then
+    # ostree can't work without initrd
+    gettext_printf "Skipping version %s (missing initrd)\n" "${version}" >&2
+    list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
+    continue
+  fi
+
+  if [ "x$is_first_entry" = xtrue ]; then
+    linux_entry "${OS}" "${version}" simple \
+    "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ostree=${GRUB_OSTREE_REVISION}"
+
+    submenu_indentation="\t"
+    
+    if [ -z "$boot_device_id" ]; then
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+    fi
+    # TRANSLATORS: %s is replaced with an OS name
+    echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {"
+  fi
+
+  linux_entry "${OS}" "${version}" advanced \
+              "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ostree=${GRUB_OSTREE_REVISION}"
+  if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+    linux_entry "${OS}" "${version}" recovery \
+                "single ${GRUB_CMDLINE_LINUX} ostree=${GRUB_OSTREE_REVISION}"
+  fi
+
+  list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
+  is_first_entry=false
+done
+
+# If at least one kernel was found, then we need to
+# add a closing '}' for the submenu command.
+if [ x"$is_first_entry" != xtrue ]; then
+  echo '}'
+fi
+
+echo "$title_correction_code"
diff --git a/src/ostree/kernel/15_ostree_remove b/src/ostree/kernel/15_ostree_remove
new file mode 100755 (executable)
index 0000000..53b2a6e
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+version=$1
+
+if [ -z "$version" ]; then
+    echo "$0: kernel version required"
+    exit 1
+fi
+
+rm -fR "/ostree/modules/${version}"
+rm -fR "/boot/initramfs-ostree-${version}.img"
diff --git a/src/ostree/kernel/15_ostree_update b/src/ostree/kernel/15_ostree_update
new file mode 100755 (executable)
index 0000000..4cdac1c
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+version=$1
+
+if [ -z "$version" ]; then
+    echo "$0: kernel version required"
+    exit 1
+fi
+
+ostadmin update-kernel current/ ${version}
index 72231ab3c0dd0efa9773b329d3dac48c89d4dc87..994a83733435f52a0046822c4b1905fd360ad667 100644 (file)
@@ -31,6 +31,7 @@
 #include "ot-builtins.h"
 
 static OstreeCommand commands[] = {
+  { "admin", ostree_builtin_admin, OSTREE_BUILTIN_FLAG_NO_REPO },
   { "cat", ostree_builtin_cat, 0 },
   { "commit", ostree_builtin_commit, 0 },
   { "config", ostree_builtin_config, 0 },
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
new file mode 100644 (file)
index 0000000..f81404f
--- /dev/null
@@ -0,0 +1,594 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "ostree.h"
+
+#include <glib/gi18n.h>
+
+typedef struct {
+  OstreeRepo  *repo;
+  GFile *ostree_dir;
+} OtAdminDeploy;
+
+static gboolean opt_no_kernel;
+static gboolean opt_force;
+
+static GOptionEntry options[] = {
+  { "no-kernel", 0, 0, G_OPTION_ARG_NONE, &opt_no_kernel, "Don't update kernel related config (initramfs, bootloader)", NULL },
+  { "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Overwrite any existing deployment", NULL },
+  { NULL }
+};
+
+/**
+ * update_current:
+ *
+ * Atomically swap the /ostree/current symbolic link to point to a new
+ * path.  If successful, the old current will be saved as
+ * /ostree/previous.
+ *
+ * Unless the new-current equals current, in which case, do nothing.
+ */
+static gboolean
+update_current (OtAdminDeploy      *self,
+                GFile              *current_deployment,
+                GFile              *deploy_target,
+                GCancellable       *cancellable,
+                GError            **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *current_path = NULL;
+  ot_lobj GFile *previous_path = NULL;
+  ot_lobj GFile *tmp_current_path = NULL;
+  ot_lobj GFile *tmp_previous_path = NULL;
+  ot_lobj GFileInfo *previous_info = NULL;
+  ot_lfree char *relative_current = NULL;
+  ot_lfree char *relative_previous = NULL;
+
+  current_path = g_file_get_child (self->ostree_dir, "current");
+  previous_path = g_file_get_child (self->ostree_dir, "previous");
+
+  relative_current = g_file_get_relative_path (self->ostree_dir, deploy_target);
+  g_assert (relative_current);
+
+  if (current_deployment)
+    {
+      ot_lfree char *relative_previous = NULL;
+
+      if (g_file_equal (current_deployment, deploy_target))
+        {
+          g_print ("ostadmin: %s already points to %s\n", ot_gfile_get_path_cached (current_path),
+                   relative_current);
+          return TRUE;
+        }
+
+      tmp_previous_path = g_file_get_child (self->ostree_dir, "tmp-previous");
+      (void) ot_gfile_unlink (tmp_previous_path, NULL, NULL);
+
+      relative_previous = g_file_get_relative_path (self->ostree_dir, current_deployment);
+      g_assert (relative_previous);
+      if (symlink (relative_previous, ot_gfile_get_path_cached (tmp_previous_path)) < 0)
+        {
+          ot_util_set_error_from_errno (error, errno);
+          goto out;
+        }
+    }
+
+  tmp_current_path = g_file_get_child (self->ostree_dir, "tmp-current");
+  (void) ot_gfile_unlink (tmp_current_path, NULL, NULL);
+
+  if (symlink (relative_current, ot_gfile_get_path_cached (tmp_current_path)) < 0)
+    {
+      ot_util_set_error_from_errno (error, errno);
+      goto out;
+    }
+
+  if (!ot_gfile_rename (tmp_current_path, current_path,
+                        cancellable, error))
+    goto out;
+
+  if (tmp_previous_path)
+    {
+      if (!ot_gfile_rename (tmp_previous_path, previous_path,
+                            cancellable, error))
+        goto out;
+    }
+
+  g_print ("ostadmin: %s set to %s\n", ot_gfile_get_path_cached (current_path),
+           relative_current);
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+typedef struct {
+  GError **error;
+  gboolean caught_error;
+
+  GMainLoop *loop;
+} ProcessOneCheckoutData;
+
+static void
+on_checkout_complete (GObject         *object,
+                      GAsyncResult    *result,
+                      gpointer         user_data)
+{
+  ProcessOneCheckoutData *data = user_data;
+  GError *local_error = NULL;
+
+  if (!ostree_repo_checkout_tree_finish ((OstreeRepo*)object, result,
+                                         &local_error))
+    goto out;
+
+ out:
+  if (local_error)
+    {
+      data->caught_error = TRUE;
+      g_propagate_error (data->error, local_error);
+    }
+  g_main_loop_quit (data->loop);
+}
+
+
+/**
+ * ensure_unlinked:
+ *
+ * Like ot_gfile_unlink(), but return successfully if the file doesn't
+ * exist.
+ */
+static gboolean
+ensure_unlinked (GFile         *path,
+                 GCancellable  *cancellable,
+                 GError       **error)
+{
+  gboolean ret = FALSE;
+  GError *temp_error = NULL;
+
+  if (!ot_gfile_unlink (path, cancellable, &temp_error))
+    {
+      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+        {
+          g_clear_error (&temp_error);
+        }
+      else
+        {
+          g_propagate_error (error, temp_error);
+          goto out;
+        }
+    }
+  
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+/**
+ * copy_one_config_file:
+ *
+ * Copy @file from @modified_etc to @new_etc, overwriting any existing
+ * file there.
+ */
+static gboolean
+copy_one_config_file (OtAdminDeploy      *self,
+                      GFile              *orig_etc,
+                      GFile              *modified_etc,
+                      GFile              *new_etc,
+                      GFile              *src,
+                      GCancellable       *cancellable,
+                      GError            **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *dest = NULL;
+  ot_lobj GFile *parent = NULL;
+  ot_lfree char *relative_path = NULL;
+  ot_lobj GFile *modified_path = NULL;
+  
+  relative_path = g_file_get_relative_path (orig_etc, src);
+  modified_path = g_file_resolve_relative_path (modified_etc, relative_path);
+  dest = g_file_resolve_relative_path (new_etc, relative_path);
+
+  parent = g_file_get_parent (dest);
+
+  /* FIXME actually we need to copy permissions and xattrs */
+  if (!ot_gfile_ensure_directory (parent, TRUE, error))
+    goto out;
+
+  if (!g_file_copy (src, dest, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA,
+                    cancellable, NULL, NULL, error))
+    goto out;
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+/**
+ * merge_etc_changes:
+ *
+ * Compute the difference between @orig_etc and @modified_etc,
+ * and apply that to @new_etc.
+ *
+ * The algorithm for computing the difference is pretty simple; it's
+ * approximately equivalent to "diff -unR orig_etc modified_etc",
+ * except that rather than attempting a 3-way merge if a file is also
+ * changed in @new_etc, the modified version always wins.
+ */
+static gboolean
+merge_etc_changes (OtAdminDeploy  *self,
+                   GFile          *orig_etc,
+                   GFile          *modified_etc,
+                   GFile          *new_etc,
+                   GCancellable   *cancellable,
+                   GError        **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *ostree_etc = NULL;
+  ot_lobj GFile *tmp_etc = NULL;
+  ot_lptrarray GPtrArray *modified = NULL;
+  ot_lptrarray GPtrArray *removed = NULL;
+  ot_lptrarray GPtrArray *added = NULL;
+  guint i;
+
+  modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
+  removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+  added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+
+  if (!ostree_diff_dirs (orig_etc, modified_etc, modified, removed, added,
+                         cancellable, error))
+    {
+      g_prefix_error (error, "While computing configuration diff: ");
+      goto out;
+    }
+
+  if (modified->len > 0 || removed->len > 0 || added->len > 0)
+    g_print ("ostadmin: Processing config: %u modified, %u removed, %u added\n", 
+             modified->len,
+             removed->len,
+             added->len);
+  else
+    g_print ("ostadmin: No modified configuration\n");
+
+  for (i = 0; i < removed->len; i++)
+    {
+      GFile *file = removed->pdata[i];
+      ot_lobj GFile *target_file = NULL;
+      ot_lfree char *path = NULL;
+
+      path = g_file_get_relative_path (orig_etc, file);
+      g_assert (path);
+      target_file = g_file_resolve_relative_path (new_etc, path);
+
+      if (!ensure_unlinked (target_file, cancellable, error))
+        goto out;
+    }
+
+  for (i = 0; i < modified->len; i++)
+    {
+      OstreeDiffItem *diff = modified->pdata[i];
+      ot_lfree char *relative_path = NULL;
+      ot_lobj GFile *modified_path = NULL;
+      ot_lobj GFile *target_path = NULL;
+      
+      relative_path = g_file_get_relative_path (orig_etc, diff->src);
+      modified_path = g_file_resolve_relative_path (modified_etc, relative_path);
+      target_path = g_file_resolve_relative_path (new_etc, relative_path);
+
+      if (!copy_one_config_file (self, orig_etc, modified_etc, new_etc, diff->src,
+                                 cancellable, error))
+        goto out;
+    }
+  for (i = 0; i < added->len; i++)
+    {
+      GFile *file = added->pdata[i];
+
+      if (!copy_one_config_file (self, orig_etc, modified_etc, new_etc, file,
+                                 cancellable, error))
+        goto out;
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+/**
+ * deploy_tree:
+ *
+ * Look up @revision in the repository, and check it out in
+ * OSTREE_DIR/deploy/DEPLOY_TARGET.
+ *
+ * Merge configuration changes from the old deployment, if any.
+ *
+ * Update the OSTREE_DIR/current and OSTREE_DIR/previous symbolic
+ * links.
+ */
+static gboolean
+deploy_tree (OtAdminDeploy     *self,
+             const char        *deploy_target,
+             const char        *revision,
+             GFile            **out_deploy_dir,           
+             GCancellable      *cancellable,
+             GError           **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *deploy_dir = NULL;
+  ot_lfree char *deploy_target_fullname = NULL;
+  ot_lfree char *deploy_target_fullname_tmp = NULL;
+  ot_lobj GFile *deploy_target_path = NULL;
+  ot_lobj GFile *deploy_target_path_tmp = NULL;
+  ot_lfree char *deploy_target_etc_name = NULL;
+  ot_lobj GFile *deploy_target_etc_path = NULL;
+  ot_lobj GFile *deploy_target_default_etc_path = NULL;
+  ot_lobj GFile *deploy_parent = NULL;
+  ot_lobj GFile *previous_deployment = NULL;
+  ot_lobj GFile *previous_deployment_etc = NULL;
+  ot_lobj GFile *previous_deployment_etc_default = NULL;
+  ot_lobj OstreeRepoFile *root = NULL;
+  ot_lobj GFileInfo *file_info = NULL;
+  ot_lobj GFileInfo *existing_checkout_info = NULL;
+  ot_lfree char *checkout_target_name = NULL;
+  ot_lfree char *checkout_target_tmp_name = NULL;
+  ot_lfree char *resolved_commit = NULL;
+  GError *temp_error = NULL;
+  gboolean skip_checkout;
+
+  if (!revision)
+    revision = deploy_target;
+
+  deploy_dir = g_file_get_child (self->ostree_dir, "deploy");
+
+  if (!ostree_repo_resolve_rev (self->repo, revision, FALSE, &resolved_commit, error))
+    goto out;
+
+  root = (OstreeRepoFile*)ostree_repo_file_new_root (self->repo, resolved_commit);
+  if (!ostree_repo_file_ensure_resolved (root, error))
+    goto out;
+
+  file_info = g_file_query_info ((GFile*)root, OSTREE_GIO_FAST_QUERYINFO,
+                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                 cancellable, error);
+  if (!file_info)
+    goto out;
+
+  deploy_target_fullname = g_strconcat (deploy_target, "-", resolved_commit, NULL);
+  deploy_target_path = g_file_resolve_relative_path (deploy_dir, deploy_target_fullname);
+
+  deploy_target_fullname_tmp = g_strconcat (deploy_target_fullname, ".tmp", NULL);
+  deploy_target_path_tmp = g_file_resolve_relative_path (deploy_dir, deploy_target_fullname_tmp);
+
+  deploy_parent = g_file_get_parent (deploy_target_path);
+  if (!ot_gfile_ensure_directory (deploy_parent, TRUE, error))
+    goto out;
+
+  deploy_target_etc_name = g_strconcat (deploy_target, "-", resolved_commit, "-etc", NULL);
+  deploy_target_etc_path = g_file_resolve_relative_path (deploy_dir, deploy_target_etc_name);
+
+  /* Delete any previous temporary data */
+  if (!ot_gio_shutil_rm_rf (deploy_target_path_tmp, cancellable, error))
+    goto out;
+
+  existing_checkout_info = g_file_query_info (deploy_target_path, OSTREE_GIO_FAST_QUERYINFO,
+                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                              cancellable, &temp_error);
+  if (existing_checkout_info)
+    {
+      if (opt_force)
+        {
+          if (!ot_gio_shutil_rm_rf (deploy_target_path, cancellable, error))
+            goto out;
+          if (!ot_gio_shutil_rm_rf (deploy_target_etc_path, cancellable, error))
+            goto out;
+          
+          skip_checkout = FALSE;
+        }
+      else
+        skip_checkout = TRUE;
+    }
+  else if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+    {
+      g_clear_error (&temp_error);
+      skip_checkout = FALSE;
+    }
+  else
+    {
+      g_propagate_error (error, temp_error);
+      goto out;
+    }
+
+  if (!ot_admin_get_current_deployment (self->ostree_dir, &previous_deployment,
+                                        cancellable, error))
+    goto out;
+  if (previous_deployment)
+    {
+      ot_lfree char *etc_name;
+      ot_lobj GFile *parent;
+
+      etc_name = g_strconcat (ot_gfile_get_basename_cached (previous_deployment), "-etc", NULL);
+      parent = g_file_get_parent (previous_deployment);
+
+      previous_deployment_etc = g_file_get_child (parent, etc_name);
+
+      if (!g_file_query_exists (previous_deployment_etc, cancellable)
+          || g_file_equal (previous_deployment, deploy_target_path))
+        g_clear_object (&previous_deployment_etc);
+      else
+        previous_deployment_etc_default = g_file_get_child (previous_deployment, "etc");
+    }
+
+
+  if (!skip_checkout)
+    {
+      ProcessOneCheckoutData checkout_data;
+
+      g_print ("ostadmin: Creating deployment %s\n",
+               ot_gfile_get_path_cached (deploy_target_path));
+
+      memset (&checkout_data, 0, sizeof (checkout_data));
+      checkout_data.loop = g_main_loop_new (NULL, TRUE);
+      checkout_data.error = error;
+
+      ostree_repo_checkout_tree_async (self->repo, 0, 0, deploy_target_path_tmp, root,
+                                       file_info, cancellable,
+                                       on_checkout_complete, &checkout_data);
+
+      g_main_loop_run (checkout_data.loop);
+
+      g_main_loop_unref (checkout_data.loop);
+
+      if (checkout_data.caught_error)
+        goto out;
+
+      if (!ostree_run_triggers_in_root (deploy_target_path_tmp, cancellable, error))
+        goto out;
+
+      deploy_target_default_etc_path = ot_gfile_get_child_strconcat (deploy_target_path_tmp, "etc", NULL);
+
+      if (!ot_gio_shutil_rm_rf (deploy_target_etc_path, cancellable, error))
+        goto out;
+
+      if (!ot_gio_shutil_cp_a (deploy_target_default_etc_path, deploy_target_etc_path,
+                               cancellable, error))
+        goto out;
+
+      g_print ("ostadmin: Created %s\n", ot_gfile_get_path_cached (deploy_target_etc_path));
+
+      if (previous_deployment_etc)
+        {
+          if (!merge_etc_changes (self, previous_deployment_etc_default,
+                                  previous_deployment_etc, deploy_target_etc_path, 
+                                  cancellable, error))
+            goto out;
+        }
+      else
+        g_print ("ostadmin: No previous deployment; therefore, no configuration changes to merge\n");
+
+      if (!ot_gfile_rename (deploy_target_path_tmp, deploy_target_path,
+                            cancellable, error))
+        goto out;
+    }
+
+  if (!update_current (self, previous_deployment, deploy_target_path,
+                       cancellable, error))
+    goto out;
+
+  ret = TRUE;
+  ot_transfer_out_value (out_deploy_dir, &deploy_target_path);
+ out:
+  return ret;
+}
+
+/**
+ * do_update_kernel:
+ *
+ * Ensure we have a GRUB entry, initramfs set up, etc.
+ */
+static gboolean
+do_update_kernel (OtAdminDeploy     *self,
+                  GFile             *deploy_path,
+                  GCancellable      *cancellable,
+                  GError           **error)
+{
+  gboolean ret = FALSE;
+  ot_lptrarray GPtrArray *args = NULL;
+
+  args = g_ptr_array_new ();
+  ot_ptrarray_add_many (args, "ostree", "admin",
+                        "--ostree-dir", ot_gfile_get_path_cached (self->ostree_dir),
+                        "update-kernel",
+                        ot_gfile_get_path_cached (deploy_path), NULL);
+  g_ptr_array_add (args, NULL);
+
+  if (!ot_spawn_sync_checked (ot_gfile_get_path_cached (self->ostree_dir),
+                              (char**)args->pdata, NULL, G_SPAWN_SEARCH_PATH,
+                              NULL, NULL, NULL, NULL, error))
+    goto out;
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+
+gboolean
+ot_admin_builtin_deploy (int argc, char **argv, GFile *ostree_dir, GError **error)
+{
+  GOptionContext *context;
+  OtAdminDeploy self_data;
+  OtAdminDeploy *self = &self_data;
+  gboolean ret = FALSE;
+  ot_lobj GFile *repo_path = NULL;
+  ot_lobj GFile *deploy_path = NULL;
+  const char *deploy_target = NULL;
+  const char *revision = NULL;
+  __attribute__((unused)) GCancellable *cancellable = NULL;
+
+  memset (self, 0, sizeof (*self));
+
+  context = g_option_context_new ("NAME [REVISION] - Check out revision NAME (or REVISION as NAME)");
+
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  if (argc < 2)
+    {
+      ot_util_usage_error (context, "NAME must be specified", error);
+      goto out;
+    }
+
+  self->ostree_dir = g_object_ref (ostree_dir);
+
+  if (!ot_admin_ensure_initialized (self->ostree_dir, cancellable, error))
+    goto out;
+
+  repo_path = g_file_get_child (self->ostree_dir, "repo");
+  self->repo = ostree_repo_new (repo_path);
+  if (!ostree_repo_check (self->repo, error))
+    goto out;
+
+  deploy_target = argv[1];
+  if (argc > 2)
+    revision = argv[2];
+
+  if (!deploy_tree (self, deploy_target, revision, &deploy_path,
+                    cancellable, error))
+    goto out;
+
+  if (!opt_no_kernel)
+    {
+      if (!do_update_kernel (self, deploy_path, cancellable, error))
+        goto out;
+    }
+
+  ret = TRUE;
+ out:
+  g_clear_object (&self->repo);
+  g_clear_object (&self->ostree_dir);
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c
new file mode 100644 (file)
index 0000000..a5c347d
--- /dev/null
@@ -0,0 +1,96 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "ostree.h"
+
+#include <glib/gi18n.h>
+
+static GOptionEntry options[] = {
+  { NULL }
+};
+
+gboolean
+ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error)
+{
+  GOptionContext *context;
+  gboolean ret = FALSE;
+  ot_lobj GFile *repo_path = NULL;
+  ot_lobj GFile *deployment = NULL;
+  ot_lobj GFile *deploy_parent = NULL;
+  ot_lptrarray GPtrArray *modified = NULL;
+  ot_lptrarray GPtrArray *removed = NULL;
+  ot_lptrarray GPtrArray *added = NULL;
+  ot_lobj GFile *orig_etc_path = NULL;
+  ot_lobj GFile *new_etc_path = NULL;
+  __attribute__((unused)) GCancellable *cancellable = NULL;
+
+  context = g_option_context_new ("[NAME] - Diff configuration for revision NAME");
+
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+  
+  repo_path = g_file_get_child (ostree_dir, "repo");
+
+  if (argc > 1)
+    {
+      deployment = ot_gfile_get_child_build_path (ostree_dir, "deploy", argv[1], NULL);
+      if (!g_file_query_exists (deployment, NULL))
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Deployment %s doesn't exist", ot_gfile_get_path_cached (deployment));
+          goto out;
+        }
+    }
+  else
+    {
+      if (!ot_admin_get_current_deployment (ostree_dir, &deployment,
+                                            cancellable, error))
+        goto out;
+    }
+
+  orig_etc_path = g_file_resolve_relative_path (deployment, "etc");
+  deploy_parent = g_file_get_parent (deployment);
+  new_etc_path = ot_gfile_get_child_strconcat (deploy_parent,
+                                               ot_gfile_get_basename_cached (deployment),
+                                               "-etc", NULL);
+  
+  modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
+  removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+  added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+  if (!ostree_diff_dirs (orig_etc_path, new_etc_path, modified, removed, added,
+                         cancellable, error))
+    goto out;
+
+  ostree_diff_print (new_etc_path, modified, removed, added);
+
+  ret = TRUE;
+ out:
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
diff --git a/src/ostree/ot-admin-builtin-init.c b/src/ostree/ot-admin-builtin-init.c
new file mode 100644 (file)
index 0000000..f433176
--- /dev/null
@@ -0,0 +1,59 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "otutil.h"
+
+#include <glib/gi18n.h>
+
+static GOptionEntry options[] = {
+  { NULL }
+};
+
+gboolean
+ot_admin_builtin_init (int argc, char **argv, GFile *ostree_dir, GError **error)
+{
+  GOptionContext *context;
+  gboolean ret = FALSE;
+  ot_lobj GFile *dir = NULL;
+  __attribute__((unused)) GCancellable *cancellable = NULL;
+
+  context = g_option_context_new ("- Initialize /ostree directory");
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  if (!ot_admin_ensure_initialized (ostree_dir, cancellable, error))
+    goto out;
+
+  g_print ("%s initialized as OSTree root\n", ot_gfile_get_path_cached (ostree_dir));
+
+  ret = TRUE;
+ out:
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
diff --git a/src/ostree/ot-admin-builtin-update-kernel.c b/src/ostree/ot-admin-builtin-update-kernel.c
new file mode 100644 (file)
index 0000000..d69b57b
--- /dev/null
@@ -0,0 +1,327 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ostree.h"
+
+#include <glib/gi18n.h>
+#include <sys/utsname.h>
+
+typedef struct {
+  GFile       *ostree_dir;
+} OtAdminUpdateKernel;
+
+static GOptionEntry options[] = {
+  { NULL }
+};
+
+static gboolean
+copy_modules (OtAdminUpdateKernel *self,
+              const char          *release,
+              GCancellable        *cancellable,
+              GError             **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *src_modules_file = NULL;
+  ot_lobj GFile *dest_modules_parent = NULL;
+  ot_lobj GFile *dest_modules_file = NULL;
+  
+  src_modules_file = ot_gfile_from_build_path ("/lib/modules", release, NULL);
+  dest_modules_file = ot_gfile_get_child_build_path (self->ostree_dir, "modules", release, NULL);
+  dest_modules_parent = g_file_get_parent (dest_modules_file);
+  if (!ot_gfile_ensure_directory (dest_modules_parent, FALSE, error))
+    goto out;
+
+  if (!g_file_query_exists (dest_modules_file, cancellable))
+    {
+      if (!ot_gio_shutil_cp_al_or_fallback (src_modules_file, dest_modules_file, cancellable, error))
+        goto out;
+    }
+      
+  ret = TRUE;
+ out:
+  if (error)
+    g_prefix_error (error, "Error copying kernel modules: ");
+  return ret;
+}
+
+static gboolean
+update_initramfs (OtAdminUpdateKernel  *self,
+                  const char           *release,
+                  const char           *deploy_path,
+                  GCancellable         *cancellable,
+                  GError              **error)
+{
+  gboolean ret = FALSE;
+  ot_lfree char *initramfs_name = NULL;
+  ot_lobj GFile *initramfs_file = NULL;
+
+  initramfs_name = g_strconcat ("initramfs-ostree-", release, ".img", NULL);
+  initramfs_file = ot_gfile_from_build_path ("/boot", initramfs_name, NULL);
+  if (!g_file_query_exists (initramfs_file, NULL))
+    {
+      ot_lptrarray GPtrArray *mkinitramfs_args = NULL;
+      ot_lobj GFile *tmpdir = NULL;
+      ot_lfree char *initramfs_tmp_path = NULL;
+      ot_lfree GFile *ostree_vardir = NULL;
+      ot_lfree GFile *ostree_moduledir = NULL;
+      ot_lobj GFile *initramfs_tmp_file = NULL;
+      ot_lobj GFileInfo *initramfs_tmp_info = NULL;
+          
+      if (!ostree_create_temp_dir (NULL, "ostree-initramfs", NULL, &tmpdir,
+                                   cancellable, error))
+        goto out;
+
+      ostree_vardir = g_file_get_child (self->ostree_dir, "var");
+      ostree_moduledir = g_file_get_child (self->ostree_dir, "modules");
+
+      mkinitramfs_args = g_ptr_array_new ();
+      /* Note: the hardcoded /tmp path below is not actually a
+       * security flaw, because we've bind-mounted dracut's view
+       * of /tmp to the securely-created tmpdir above.
+       */
+      ot_ptrarray_add_many (mkinitramfs_args,
+                            "linux-user-chroot",
+                            "--mount-readonly", "/",
+                            "--mount-proc", "/proc",
+                            "--mount-bind", "/dev", "/dev",
+                            "--mount-bind", ot_gfile_get_path_cached (ostree_vardir), "/var",
+                            "--mount-bind", ot_gfile_get_path_cached (tmpdir), "/tmp",
+                            "--mount-bind", ot_gfile_get_path_cached (ostree_moduledir), "/lib/modules",
+                            deploy_path,
+                            "dracut", "-f", "/tmp/initramfs-ostree.img", release,
+                            NULL);
+      g_ptr_array_add (mkinitramfs_args, NULL);
+          
+      g_print ("Generating initramfs using %s...\n", deploy_path);
+      if (!ot_spawn_sync_checked (NULL, (char**)mkinitramfs_args->pdata, NULL,
+                                  G_SPAWN_SEARCH_PATH,
+                                  NULL, NULL, NULL, NULL, error))
+        goto out;
+          
+      initramfs_tmp_file = g_file_get_child (tmpdir, "initramfs-ostree.img");
+      initramfs_tmp_info = g_file_query_info (initramfs_tmp_file, OSTREE_GIO_FAST_QUERYINFO,
+                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                              cancellable, error);
+      if (!initramfs_tmp_info)
+        goto out;
+
+      if (g_file_info_get_size (initramfs_tmp_info) == 0)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Initramfs generation failed, check dracut.log");
+          goto out;
+        }
+
+      if (!g_file_copy (initramfs_tmp_file, initramfs_file, 0, cancellable, NULL, NULL, error))
+        goto out;
+          
+      g_print ("Created: %s\n", ot_gfile_get_path_cached (initramfs_file));
+
+      (void) ot_gfile_unlink (initramfs_tmp_file, NULL, NULL);
+      (void) rmdir (ot_gfile_get_path_cached (tmpdir));
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+static gboolean
+grep_literal (GFile              *f,
+              const char         *string,
+              gboolean           *out_matches,
+              GCancellable       *cancellable,
+              GError            **error)
+{
+  gboolean ret = FALSE;
+  gboolean ret_matches = FALSE;
+  ot_lobj GInputStream *in = NULL;
+  ot_lobj GDataInputStream *datain = NULL;
+  ot_lfree char *line = NULL;
+
+  in = (GInputStream*)g_file_read (f, cancellable, error);
+  if (!in)
+    goto out;
+  datain = (GDataInputStream*)g_data_input_stream_new (in);
+  if (!in)
+    goto out;
+
+  while ((line = g_data_input_stream_read_line (datain, NULL, cancellable, error)) != NULL)
+    {
+      if (strstr (line, string))
+        {
+          ret_matches = TRUE;
+          break;
+        }
+      
+      g_free (line);
+    }
+
+  ret = TRUE;
+  if (out_matches)
+    *out_matches = ret_matches;
+ out:
+  return ret;
+}
+
+static gboolean
+get_kernel_path_from_release (OtAdminUpdateKernel  *self,
+                              const char           *release,
+                              GFile               **out_path,
+                              GCancellable         *cancellable,
+                              GError              **error)
+{
+  gboolean ret = FALSE;
+  ot_lfree char *name = NULL;
+  ot_lobj GFile *possible_path = NULL;
+
+  /* TODO - replace this with grubby code */
+
+  name = g_strconcat ("vmlinuz-", release, NULL);
+  possible_path = ot_gfile_from_build_path ("/boot", name, NULL);
+  if (!g_file_query_exists (possible_path, cancellable))
+    g_clear_object (&possible_path);
+
+  ret = TRUE;
+  ot_transfer_out_value (out_path, &possible_path);
+  /*  out: */
+  return ret;
+}
+
+static gboolean
+update_grub (OtAdminUpdateKernel  *self,
+             const char           *release,
+             GCancellable         *cancellable,
+             GError              **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *grub_path = g_file_new_for_path ("/boot/grub/grub.conf");
+
+  if (g_file_query_exists (grub_path, cancellable))
+    {
+      gboolean have_grub_entry;
+      if (!grep_literal (grub_path, "OSTree", &have_grub_entry,
+                         cancellable, error))
+        goto out;
+
+      if (!have_grub_entry)
+        {
+          ot_lptrarray GPtrArray *grubby_args = NULL;
+          ot_lfree char *add_kernel_arg = NULL;
+          ot_lfree char *initramfs_arg = NULL;
+          ot_lobj GFile *kernel_path = NULL;
+
+          if (!get_kernel_path_from_release (self, release, &kernel_path,
+                                             cancellable, error))
+            goto out;
+
+          if (kernel_path == NULL)
+            {
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                           "Couldn't find kernel for release %s", release);
+              goto out;
+            }
+
+          grubby_args = g_ptr_array_new ();
+          add_kernel_arg = g_strconcat ("--add-kernel=", ot_gfile_get_path_cached (kernel_path), NULL);
+          initramfs_arg = g_strconcat ("--initrd=", "/boot/initramfs-ostree-", release, ".img", NULL);
+          ot_ptrarray_add_many (grubby_args, "grubby", "--grub", add_kernel_arg, initramfs_arg,
+                                "--copy-default", "--title=OSTree", NULL);
+          g_ptr_array_add (grubby_args, NULL);
+
+          g_print ("Adding OSTree grub entry...\n");
+          if (!ot_spawn_sync_checked (NULL, (char**)grubby_args->pdata, NULL, G_SPAWN_SEARCH_PATH,
+                                      NULL, NULL, NULL, NULL, error))
+            goto out;
+        } 
+      else
+        g_print ("Already have OSTree entry in grub config\n");
+    }
+  else
+    {
+      g_print ("/boot/grub/grub.conf not found, assuming you have GRUB 2\n");
+    }
+  
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+gboolean
+ot_admin_builtin_update_kernel (int argc, char **argv, GFile *ostree_dir, GError **error)
+{
+  GOptionContext *context;
+  OtAdminUpdateKernel self_data;
+  OtAdminUpdateKernel *self = &self_data;
+  gboolean ret = FALSE;
+  const char *deploy_path = NULL;
+  struct utsname utsname;
+  const char *release;
+  __attribute__((unused)) GCancellable *cancellable = NULL;
+
+  memset (self, 0, sizeof (*self));
+
+  context = g_option_context_new ("[OSTREE_REVISION [KERNEL_RELEASE]] - Update kernel and regenerate initial ramfs");
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  if (argc > 1)
+    deploy_path = argv[1];
+  else
+    deploy_path = "current";
+
+  (void) uname (&utsname);
+  
+  if (strcmp (utsname.sysname, "Linux") != 0)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Unsupported machine %s", utsname.sysname);
+      goto out;
+    }
+  
+  release = utsname.release;
+  if (argc > 2)
+    release = argv[2];
+
+  self->ostree_dir = g_object_ref (ostree_dir);
+  
+  if (!copy_modules (self, release, cancellable, error))
+    goto out;
+  
+  if (!update_initramfs (self, release, deploy_path, cancellable, error))
+    goto out;
+  
+  if (!update_grub (self, release, cancellable, error))
+    goto out;
+
+  ret = TRUE;
+ out:
+  g_clear_object (&self->ostree_dir);
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
diff --git a/src/ostree/ot-admin-builtins.h b/src/ostree/ot-admin-builtins.h
new file mode 100644 (file)
index 0000000..f9e60d7
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#ifndef __OT_ADMIN_BUILTINS__
+#define __OT_ADMIN_BUILTINS__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+gboolean ot_admin_builtin_init (int argc, char **argv, GFile *ostree_dir, GError **error);
+gboolean ot_admin_builtin_deploy (int argc, char **argv, GFile *ostree_dir, GError **error);
+gboolean ot_admin_builtin_diff (int argc, char **argv, GFile *ostree_dir, GError **error);
+gboolean ot_admin_builtin_update_kernel (int argc, char **argv, GFile *ostree_dir, GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
new file mode 100644 (file)
index 0000000..5209685
--- /dev/null
@@ -0,0 +1,144 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#include "config.h"
+
+#include "ot-admin-functions.h"
+#include "otutil.h"
+#include "ostree-core.h"
+
+gboolean
+ot_admin_ensure_initialized (GFile         *ostree_dir,
+                             GCancellable  *cancellable,
+                             GError       **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *dir = NULL;
+
+  g_clear_object (&dir);
+  dir = g_file_get_child (ostree_dir, "repo");
+  if (!ot_gfile_ensure_directory (dir, TRUE, error))
+    goto out;
+
+  g_clear_object (&dir);
+  dir = g_file_get_child (ostree_dir, "deploy");
+  if (!ot_gfile_ensure_directory (dir, TRUE, error))
+    goto out;
+
+  g_clear_object (&dir);
+  dir = g_file_get_child (ostree_dir, "modules");
+  if (!ot_gfile_ensure_directory (dir, TRUE, error))
+    goto out;
+
+  g_clear_object (&dir);
+  dir = ot_gfile_get_child_build_path (ostree_dir, "repo", "objects", NULL);
+  if (!g_file_query_exists (dir, NULL))
+    {
+      ot_lfree char *opt_repo_arg = g_strdup_printf ("--repo=%s/repo",
+                                                      ot_gfile_get_path_cached (ostree_dir));
+      const char *child_argv[] = { "ostree", opt_repo_arg, "init", NULL };
+
+      if (!ot_spawn_sync_checked (NULL, (char**)child_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
+                                  NULL, NULL, error))
+        {
+          g_prefix_error (error, "Failed to initialize repository: ");
+          goto out;
+        }
+    }
+
+  /* Ensure a few subdirectories of /var exist, since we need them for
+     dracut generation */
+  g_clear_object (&dir);
+  dir = ot_gfile_get_child_build_path (ostree_dir, "var", "log", NULL);
+  if (!ot_gfile_ensure_directory (dir, TRUE, error))
+    goto out;
+  g_clear_object (&dir);
+  dir = ot_gfile_get_child_build_path (ostree_dir, "var", "tmp", NULL);
+  if (!ot_gfile_ensure_directory (dir, TRUE, error))
+    goto out;
+  if (chmod (ot_gfile_get_path_cached (dir), 01777) < 0)
+    {
+      ot_util_set_error_from_errno (error, errno);
+      goto out;
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+/**
+ * ot_admin_get_current_deployment:
+ * 
+ * Returns in @out_deployment the full file path of the current
+ * deployment that the /ostree/current symbolic link points to, or
+ * %NULL if none.
+ */
+gboolean
+ot_admin_get_current_deployment (GFile           *ostree_dir,
+                                 GFile          **out_deployment,
+                                 GCancellable    *cancellable,
+                                 GError         **error)
+{
+  gboolean ret = FALSE;
+  ot_lobj GFile *current_path = NULL;
+  ot_lobj GFileInfo *file_info = NULL;
+  ot_lobj GFile *ret_deployment = NULL;
+  GError *temp_error = NULL;
+
+  current_path = g_file_get_child (ostree_dir, "current");
+
+  file_info = g_file_query_info (current_path, OSTREE_GIO_FAST_QUERYINFO,
+                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                 cancellable, &temp_error);
+  if (!file_info)
+    {
+      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+        {
+          g_clear_error (&temp_error);
+        }
+      else
+        {
+          g_propagate_error (error, temp_error);
+          goto out;
+        }
+    }
+  else
+    {
+      const char *target;
+      if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_SYMBOLIC_LINK)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Not a symbolic link");
+          goto out;
+        }
+      target = g_file_info_get_symlink_target (file_info);
+      g_assert (target);
+      ret_deployment = g_file_resolve_relative_path (ostree_dir, target);
+    }
+
+  ret = TRUE;
+  ot_transfer_out_value (out_deployment, &ret_deployment);
+ out:
+  return ret;
+}
+
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
new file mode 100644 (file)
index 0000000..f4e1b74
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#ifndef __OT_ADMIN_FUNCTIONS__
+#define __OT_ADMIN_FUNCTIONS__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+gboolean ot_admin_ensure_initialized (GFile         *ostree_dir, 
+                                     GCancellable  *cancellable,
+                                     GError       **error);
+
+gboolean ot_admin_get_current_deployment (GFile           *ostree_dir,
+                                          GFile          **out_deployment,
+                                          GCancellable    *cancellable,
+                                          GError         **error);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c
new file mode 100644 (file)
index 0000000..f8aa8f9
--- /dev/null
@@ -0,0 +1,105 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#include "config.h"
+
+#include "ot-builtins.h"
+#include "ot-admin-builtins.h"
+#include "ot-main.h"
+#include "ostree.h"
+#include "ostree-repo-file.h"
+
+#include <glib/gi18n.h>
+
+static char *opt_ostree_dir = "/ostree";
+
+static GOptionEntry options[] = {
+  { "ostree-dir", 0, 0, G_OPTION_ARG_STRING, &opt_ostree_dir, "Path to OSTree root directory (default: /ostree)", NULL },
+  { NULL }
+};
+
+typedef struct {
+  const char *name;
+  gboolean (*fn) (int argc, char **argv, GFile *ostree_dir, GError **error);
+} OstreeAdminCommand;
+
+static OstreeAdminCommand admin_subcommands[] = {
+  { "init", ot_admin_builtin_init },
+  { "deploy", ot_admin_builtin_deploy },
+  { "update-kernel", ot_admin_builtin_update_kernel },
+  { "config-diff", ot_admin_builtin_diff },
+  { NULL, NULL }
+};
+
+gboolean
+ostree_builtin_admin (int argc, char **argv, GFile *repo_path, GError **error)
+{
+  GOptionContext *context;
+  gboolean ret = FALSE;
+  __attribute__((unused)) GCancellable *cancellable = NULL;
+  const char *subcommand_name;
+  OstreeAdminCommand *subcommand;
+  int subcmd_argc;
+  char **subcmd_argv = NULL;
+  ot_lobj GFile *ostree_dir = NULL;
+
+  context = g_option_context_new ("[OPTIONS] SUBCOMMAND - Run an administrative subcommand");
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  if (argc <= 1)
+    {
+      ot_util_usage_error (context, "A valid SUBCOMMAND is required", error);
+      goto out;
+    }
+  subcommand_name = argv[1];
+
+  subcommand = admin_subcommands;
+  while (subcommand->name)
+    {
+      if (g_strcmp0 (subcommand_name, subcommand->name) == 0)
+        break;
+      subcommand++;
+    }
+
+  if (!subcommand->name)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                   "Unknown command '%s'", subcommand_name);
+      goto out;
+    }
+
+  ostree_dir = g_file_new_for_path (opt_ostree_dir);
+
+  ostree_prep_builtin_argv (subcommand_name, argc-2, argv+2, &subcmd_argc, &subcmd_argv);
+
+  if (!subcommand->fn (subcmd_argc, subcmd_argv, ostree_dir, error))
+    goto out;
+  ret = TRUE;
+ out:
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
index b380190c167e27d912aacc63eec2ae9b39b40607..aa7a645dc4ace8d33f98d0633432732d71ab0266 100644 (file)
@@ -27,6 +27,7 @@
 
 G_BEGIN_DECLS
 
+gboolean ostree_builtin_admin (int argc, char **argv, GFile *repo_path, GError **error);
 gboolean ostree_builtin_cat (int argc, char **argv, GFile *repo_path, GError **error);
 gboolean ostree_builtin_config (int argc, char **argv, GFile *repo_path, GError **error);
 gboolean ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error);
index 90f3209bcc6f7645f181168f77a75b31a8f135b1..554307f38afdc9e2ae762a7c1748c2030b306d3d 100644 (file)
@@ -54,12 +54,12 @@ ostree_usage (char **argv,
   return (is_error ? 1 : 0);
 }
 
-static void
-prep_builtin_argv (const char *builtin,
-                   int argc,
-                   char **argv,
-                   int *out_argc,
-                   char ***out_argv)
+void
+ostree_prep_builtin_argv (const char  *builtin,
+                          int          argc,
+                          char       **argv,
+                          int         *out_argc,
+                          char      ***out_argv)
 {
   int i;
   char **cmd_argv;
@@ -165,7 +165,7 @@ ostree_run (int    argc,
       goto out;
     }
   
-  prep_builtin_argv (cmd, argc-arg_off, argv+arg_off, &cmd_argc, &cmd_argv);
+  ostree_prep_builtin_argv (cmd, argc-arg_off, argv+arg_off, &cmd_argc, &cmd_argv);
 
   if (!command->fn (cmd_argc, cmd_argv, repo_file, &error))
     goto out;
index 4deb086a25208cd009ca88d4a7f7e81924f579b3..f7e632b01fa5a04d7300d44a0e2b2cfb07893c66 100644 (file)
@@ -33,6 +33,13 @@ typedef struct {
   int flags; /* OstreeBuiltinFlags */
 } OstreeCommand;
 
+void
+ostree_prep_builtin_argv (const char  *builtin,
+                          int          argc,
+                          char       **argv,
+                          int         *out_argc,
+                          char      ***out_argv);
+
 int ostree_main (int    argc, char **argv, OstreeCommand  *commands);
 
 int ostree_run (int argc, char **argv, OstreeCommand *commands, GError **error);